As of CL 695977, under(Type) simply delegates to Type.Underlying().
This is just a cleanup.
Change-Id: I48d5fddc38560dfe485184faa6a5ff713bea74a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/712400
Commit-Queue: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
// x.typ is typed
// A generic (non-instantiated) function value cannot be assigned to a variable.
- if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
+ if sig, _ := x.typ.Underlying().(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
x.mode = invalid
return
var target *target
// avoid calling ExprString if not needed
if T != nil {
- if _, ok := under(T).(*Signature); ok {
+ if _, ok := T.Underlying().(*Signature); ok {
target = newTarget(T, ExprString(lhs))
}
}
// len(x)
mode := invalid
var val constant.Value
- switch t := arrayPtrDeref(under(x.typ)).(type) {
+ switch t := arrayPtrDeref(x.typ.Underlying()).(type) {
case *Basic:
if isString(t) && id == _Len {
if x.mode == constant_ {
if mode == invalid {
// avoid error if underlying type is invalid
- if isValid(under(x.typ)) {
+ if isValid(x.typ.Underlying()) {
code := InvalidCap
if id == _Len {
code = InvalidLen
// (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type {
assert(!isTypeParam(typ))
- if t, _ := under(typ).(*Basic); t != nil {
+ if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind {
case Float32:
return Typ[Complex64]
// (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type {
assert(!isTypeParam(typ))
- if t, _ := under(typ).(*Basic); t != nil {
+ if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind {
case Complex64:
return Typ[Float32]
}()
}
- switch u := under(t).(type) {
+ switch u := t.Underlying().(type) {
case *Array:
return hasVarSize(u.elem, seen)
case *Struct:
// otherwise it returns typ.
func arrayPtrDeref(typ Type) Type {
if p, ok := Unalias(typ).(*Pointer); ok {
- if a, _ := under(p.base).(*Array); a != nil {
+ if a, _ := p.base.Underlying().(*Array); a != nil {
return a
}
}
case 1:
check.expr(nil, x, call.ArgList[0])
if x.mode != invalid {
- if t, _ := under(T).(*Interface); t != nil && !isTypeParam(T) {
+ if t, _ := T.Underlying().(*Interface); t != nil && !isTypeParam(T) {
if !t.IsMethodSet() {
check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
break
obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
- if !isValid(under(x.typ)) {
+ if !isValid(x.typ.Underlying()) {
goto Error
}
// x.typ cannot be a type parameter (type
// parameters cannot be constant types).
if isTyped(x.typ) {
- check.representable(x, under(x.typ).(*Basic))
+ check.representable(x, x.typ.Underlying().(*Basic))
return
}
constArg := x.mode == constant_
constConvertibleTo := func(T Type, val *constant.Value) bool {
- switch t, _ := under(T).(*Basic); {
+ switch t, _ := T.Underlying().(*Basic); {
case t == nil:
// nothing to do
case representableConst(x.val, check, t, val):
origT := T
V := Unalias(x.typ)
T = Unalias(T)
- Vu := under(V)
- Tu := under(T)
+ Vu := V.Underlying()
+ Tu := T.Underlying()
Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam)
// and their pointer base types are not type parameters"
if V, ok := V.(*Pointer); ok {
if T, ok := T.(*Pointer); ok {
- if IdenticalIgnoreTags(under(V.base), under(T.base)) && !isTypeParam(V.base) && !isTypeParam(T.base) {
+ if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) && !isTypeParam(V.base) && !isTypeParam(T.base) {
return true
}
}
return false
}
case *Pointer:
- if a, _ := under(a.Elem()).(*Array); a != nil {
+ if a, _ := a.Elem().Underlying().(*Array); a != nil {
if Identical(s.Elem(), a.Elem()) {
if check == nil || check.allowVersion(go1_17) {
return true
}
func isUintptr(typ Type) bool {
- t, _ := under(typ).(*Basic)
+ t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == Uintptr
}
func isUnsafePointer(typ Type) bool {
- t, _ := under(typ).(*Basic)
+ t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == UnsafePointer
}
func isPointer(typ Type) bool {
- _, ok := under(typ).(*Pointer)
+ _, ok := typ.Underlying().(*Pointer)
return ok
}
func isBytesOrRunes(typ Type) bool {
- if s, _ := under(typ).(*Slice); s != nil {
- t, _ := under(s.elem).(*Basic)
+ if s, _ := typ.Underlying().(*Slice); s != nil {
+ t, _ := s.elem.Underlying().(*Basic)
return t != nil && (t.kind == Byte || t.kind == Rune)
}
return false
if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type
// (go.dev/issue/22090)
- if isValid(under(t)) {
+ if isValid(t.Underlying()) {
check.errorf(typ, InvalidConstType, "invalid constant type %s", t)
}
obj.typ = Typ[Invalid]
// If the new type is not final and still untyped, just
// update the recorded type.
if !final && isUntyped(typ) {
- old.typ = under(typ).(*Basic)
+ old.typ = typ.Underlying().(*Basic)
check.untyped[x] = old
return
}
return nil, nil, InvalidUntypedConversion
}
- switch u := under(target).(type) {
+ switch u := target.Underlying().(type) {
case *Basic:
if x.mode == constant_ {
v, code := check.representation(x, u)
// incomparableCause returns a more specific cause why typ is not comparable.
// If there is no more specific cause, the result is "".
func (check *Checker) incomparableCause(typ Type) string {
- switch under(typ).(type) {
+ switch typ.Underlying().(type) {
case *Slice, *Signature, *Map:
return compositeKind(typ) + " can only be compared to nil"
}
// The result is nil if typ is not a signature.
func newTarget(typ Type, desc string) *target {
if typ != nil {
- if sig, _ := under(typ).(*Signature); sig != nil {
+ if sig, _ := typ.Underlying().(*Signature); sig != nil {
return &target{sig, desc}
}
}
check.errorf(x, InvalidAssert, invalidOp+"cannot use type assertion on type parameter value %s", x)
goto Error
}
- if _, ok := under(x.typ).(*Interface); !ok {
+ if _, ok := x.typ.Underlying().(*Interface); !ok {
check.errorf(x, InvalidAssert, invalidOp+"%s is not an interface", x)
goto Error
}
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1."
}
func (s *gcSizes) Sizeof(T Type) int64 {
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Basic:
assert(isTyped(T))
k := t.kind
return false
case value:
- if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
+ if sig, _ := x.typ.Underlying().(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
// function instantiation
return true
}
// ordinary index expression
valid := false
length := int64(-1) // valid if >= 0
- switch typ := under(x.typ).(type) {
+ switch typ := x.typ.Underlying().(type) {
case *Basic:
if isString(typ) {
valid = true
x.typ = typ.elem
case *Pointer:
- if typ, _ := under(typ.base).(*Array); typ != nil {
+ if typ, _ := typ.base.Underlying().(*Array); typ != nil {
valid = true
length = typ.len
x.mode = variable
mode = value
}
case *Pointer:
- if t, _ := under(t.base).(*Array); t != nil {
+ if t, _ := t.base.Underlying().(*Array); t != nil {
l = t.len
e = t.elem
}
// but don't go from untyped string to string.
cu = Typ[String]
if !isTypeParam(x.typ) {
- cu = under(x.typ) // untyped string remains untyped
+ cu = x.typ.Underlying() // untyped string remains untyped
}
}
x.typ = &Slice{elem: u.elem}
case *Pointer:
- if u, _ := under(u.base).(*Array); u != nil {
+ if u, _ := u.base.Underlying().(*Array); u != nil {
valid = true
length = u.len
x.typ = &Slice{elem: u.elem}
if n == 1 {
if debug {
u, _ := commonUnder(tpar, nil)
- assert(under(single.typ) == u)
+ assert(single.typ.Underlying() == u)
}
return single, true
}
// If the provided cause is non-nil, it may be set to an error string
// explaining why V does not implement (or satisfy, for constraints) T.
func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool {
- Vu := under(V)
- Tu := under(T)
+ Vu := V.Underlying()
+ Tu := T.Underlying()
if !isValid(Vu) || !isValid(Tu) {
return true // avoid follow-on errors
}
- if p, _ := Vu.(*Pointer); p != nil && !isValid(under(p.base)) {
+ if p, _ := Vu.(*Pointer); p != nil && !isValid(p.base.Underlying()) {
return true // avoid follow-on errors (see go.dev/issue/49541 for an example)
}
// If V ∉ t.typ but V ∈ ~t.typ then remember this type
// so we can suggest it as an alternative in the error
// message.
- if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) {
+ if alt == nil && !t.tilde && Identical(t.typ, t.typ.Underlying()) {
tt := *t
tt.tilde = true
if tt.includes(V) {
// *typ where typ is an interface (incl. a type parameter) has no methods.
if isPtr {
- if _, ok := under(typ).(*Interface); ok {
+ if _, ok := typ.Underlying().(*Interface); ok {
return
}
}
}
}
- switch t := under(typ).(type) {
+ switch t := typ.Underlying().(type) {
case *Struct:
// look for a matching field and collect embedded types
for i, f := range t.fields {
// The comparator is used to compare signatures.
// If a method is missing and cause is not nil, *cause describes the error.
func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y Type) bool, cause *string) (method *Func, wrongType bool) {
- methods := under(T).(*Interface).typeSet().methods // T must be an interface
+ methods := T.Underlying().(*Interface).typeSet().methods // T must be an interface
if len(methods) == 0 {
return nil, false
}
var m *Func // method on T we're trying to implement
var f *Func // method on V, if found (state is one of ok, wrongName, wrongSig)
- if u, _ := under(V).(*Interface); u != nil {
+ if u, _ := V.Underlying().(*Interface); u != nil {
tset := u.typeSet()
for _, m = range methods {
_, f = tset.LookupMethod(m.pkg, m.name, false)
// hasInvalidEmbeddedFields reports whether T is a struct (or a pointer to a struct) that contains
// (directly or indirectly) embedded fields with invalid types.
func hasInvalidEmbeddedFields(T Type, seen map[*Struct]bool) bool {
- if S, _ := under(derefStructPtr(T)).(*Struct); S != nil && !seen[S] {
+ if S, _ := derefStructPtr(T).Underlying().(*Struct); S != nil && !seen[S] {
if seen == nil {
seen = make(map[*Struct]bool)
}
}
func isInterfacePtr(T Type) bool {
- p, _ := under(T).(*Pointer)
+ p, _ := T.Underlying().(*Pointer)
return p != nil && IsInterface(p.base)
}
// check may be nil.
func (check *Checker) interfacePtrError(T Type) string {
assert(isInterfacePtr(T))
- if p, _ := under(T).(*Pointer); isTypeParam(p.base) {
+ if p, _ := T.Underlying().(*Pointer); isTypeParam(p.base) {
return check.sprintf("type %s is pointer to type parameter, not type parameter", T)
}
return check.sprintf("type %s is pointer to interface, not interface", T)
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
// (named or unnamed) struct and returns its base. Otherwise it returns typ.
func derefStructPtr(typ Type) Type {
- if p, _ := under(typ).(*Pointer); p != nil {
- if _, ok := under(p.base).(*Struct); ok {
+ if p, _ := typ.Underlying().(*Pointer); p != nil {
+ if _, ok := p.base.Underlying().(*Struct); ok {
return p.base
}
}
} else {
// TODO(gri) should this be fromRHS for *Named?
// (See discussion in #66559.)
- typ = under(typ)
+ typ = typ.Underlying()
}
}
what := compositeKind(x.typ)
if what == "" {
// x.typ must be basic type
- what = under(x.typ).(*Basic).name
+ what = x.typ.Underlying().(*Basic).name
}
desc += what + " "
}
// ("array", "slice", etc.) or the empty string if typ is not
// composite but a basic type.
func compositeKind(typ Type) string {
- switch under(typ).(type) {
+ switch typ.Underlying().(type) {
case *Basic:
return ""
case *Array:
return true, 0
}
- Vu := under(V)
- Tu := under(T)
+ Vu := V.Underlying()
+ Tu := T.Underlying()
Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam)
func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
func isConstType(t Type) bool { return isBasic(t, IsConstType) }
-// isBasic reports whether under(t) is a basic type with the specified info.
+// isBasic reports whether t.Underlying() is a basic type with the specified info.
// If t is a type parameter the result is false; i.e.,
// isBasic does not look inside a type parameter.
func isBasic(t Type, info BasicInfo) bool {
- u, _ := under(t).(*Basic)
+ u, _ := t.Underlying().(*Basic)
return u != nil && u.info&info != 0
}
func allOrdered(t Type) bool { return allBasic(t, IsOrdered) }
func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
-// allBasic reports whether under(t) is a basic type with the specified info.
+// allBasic reports whether t.Underlying() is a basic type with the specified info.
// If t is a type parameter, the result is true if isBasic(t, info) is true
// for all specific types of the type parameter's type set.
func allBasic(t Type, info BasicInfo) bool {
// IsInterface reports whether t is an interface type.
func IsInterface(t Type) bool {
- _, ok := under(t).(*Interface)
+ _, ok := t.Underlying().(*Interface)
return ok
}
}
seen[T] = true
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Basic:
// assume invalid types to be comparable to avoid follow-up errors
if t.kind == UntypedNil {
// hasNil reports whether type t includes the nil value.
func hasNil(t Type) bool {
- switch u := under(t).(type) {
+ switch u := t.Underlying().(type) {
case *Basic:
return u.kind == UnsafePointer
case *Slice, *Pointer, *Signature, *Map, *Chan:
check.expr(nil, &x, rangeVar)
if isTypes2 && x.mode != invalid && sValue == nil && !check.hasCallOrRecv {
- if t, ok := arrayPtrDeref(under(x.typ)).(*Array); ok {
+ if t, ok := arrayPtrDeref(x.typ.Underlying()).(*Array); ok {
for {
// Put constant info on the thing inside parentheses.
// That's where (*../noder/writer).expr expects it.
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1."
}
func (s *StdSizes) Sizeof(T Type) int64 {
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Basic:
assert(isTyped(T))
k := t.kind
func (conf *Config) offsetof(T Type, index []int) int64 {
var offs int64
for _, i := range index {
- s := under(T).(*Struct)
+ s := T.Underlying().(*Struct)
d := conf.offsetsof(s)[i]
if d < 0 {
return -1
// Because we have a name, typ must be of the form T or *T, where T is the name
// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
// We must delay this check to the end because we don't want to instantiate
- // (via under(t)) a possibly incomplete type.
+ // (via t.Underlying()) a possibly incomplete type.
embeddedTyp := typ // for closure below
embeddedPos := pos
check.later(func() {
t, isPtr := deref(embeddedTyp)
- switch u := under(t).(type) {
+ switch u := t.Underlying().(type) {
case *Basic:
if !isValid(t) {
// error was reported before
// determine constraint interface
var ityp *Interface
- switch u := under(bound).(type) {
+ switch u := bound.Underlying().(type) {
case *Basic:
if !isValid(u) {
// error is reported elsewhere
for _, t := range s.terms {
assert(t.typ != nil)
- // Unalias(x) == under(x) for ~x terms
+ // Unalias(x) == x.Underlying() for ~x terms
u := Unalias(t.typ)
if !t.tilde {
- u = under(u)
+ u = u.Underlying()
}
if debug {
- assert(Identical(u, under(u)))
+ assert(Identical(u, u.Underlying()))
}
if !f(t.typ, u) {
return false
}
var comparable bool
var terms termlist
- switch u := under(typ).(type) {
+ switch u := typ.Underlying().(type) {
case *Interface:
// For now we don't permit type parameters as constraints.
assert(!isTypeParam(typ))
var allTerms termlist
for _, t := range utyp.terms {
var terms termlist
- u := under(t.typ)
+ u := t.typ.Underlying()
if ui, _ := u.(*Interface); ui != nil {
// For now we don't permit type parameters as constraints.
assert(!isTypeParam(t.typ))
if obj == nil {
t.Fatalf("%s: T not found (invalid test case)", body)
}
- T, ok := under(obj.Type()).(*Interface)
+ T, ok := obj.Type().Underlying().(*Interface)
if !ok {
t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj)
}
} else {
// special case:
// append(s, "foo"...) leads to signature func([]byte, string...)
- if t, _ := under(typ).(*Basic); t == nil || t.kind != String {
+ if t, _ := typ.Underlying().(*Basic); t == nil || t.kind != String {
w.error("expected string type")
continue
}
u := t
if x.tilde {
- u = under(u)
+ u = u.Underlying()
}
return Identical(x.typ, u)
}
}
ux := x.typ
if y.tilde {
- ux = under(ux)
+ ux = ux.Underlying()
}
uy := y.typ
if x.tilde {
- uy = under(uy)
+ uy = uy.Underlying()
}
return !Identical(ux, uy)
}
return
}
- // We don't want to call under() or complete interfaces while we are in
+ // We don't want to call typ.Underlying() or complete interfaces while we are in
// the middle of type-checking parameter declarations that might belong
// to interface methods. Delay this check to the end of type-checking.
check.later(func() {
- if t, _ := under(typ).(*Interface); t != nil {
+ if t, _ := typ.Underlying().(*Interface); t != nil {
pos := syntax.StartPos(e)
tset := computeInterfaceTypeSet(check, pos, t) // TODO(gri) is this the correct position?
if !tset.IsMethodSet() {
check.indent--
var under Type
if T != nil {
- // Calling under() here may lead to endless instantiations.
+ // Calling T.Underlying() here may lead to endless instantiations.
// Test case: type T[P any] *T[P]
under = safeUnderlying(T)
}
import "iter"
-// under returns the true expanded underlying type.
-// If it doesn't exist, the result is Typ[Invalid].
-// under must only be called when a type is known
-// to be fully set up.
-func under(t Type) Type {
- // TODO(markfreeman): Remove this function, it just delegates.
- return t.Underlying()
-}
-
// If typ is a type parameter, underIs returns the result of typ.underIs(f).
-// Otherwise, underIs returns the result of f(under(typ)).
+// Otherwise, underIs returns the result of f(typ.Underlying()).
func underIs(typ Type, f func(Type) bool) bool {
return all(typ, func(_, u Type) bool {
return f(u)
if p, _ := Unalias(t).(*TypeParam); p != nil {
return p.typeset(f)
}
- return f(t, under(t))
+ return f(t, t.Underlying())
}
// typeset is an iterator over the (type/underlying type) pairs of the
// it is a non-type parameter interface. Otherwise it returns nil.
func asInterface(x Type) (i *Interface) {
if _, ok := Unalias(x).(*TypeParam); !ok {
- i, _ = under(x).(*Interface)
+ i, _ = x.Underlying().(*Interface)
}
return i
}
u.set(px, y)
default:
// Neither x nor y are defined types.
- if yc, _ := under(y).(*Chan); yc != nil && yc.dir != SendRecv {
+ if yc, _ := y.Underlying().(*Chan); yc != nil && yc.dir != SendRecv {
// y is a directed channel type: select y.
u.set(px, y)
}
continue
}
- u := under(t.typ)
+ u := t.typ.Underlying()
f, _ := u.(*Interface)
if t.tilde {
if f != nil {
// x.typ is typed
// A generic (non-instantiated) function value cannot be assigned to a variable.
- if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
+ if sig, _ := x.typ.Underlying().(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
x.mode = invalid
return
var target *target
// avoid calling ExprString if not needed
if T != nil {
- if _, ok := under(T).(*Signature); ok {
+ if _, ok := T.Underlying().(*Signature); ok {
target = newTarget(T, ExprString(lhs))
}
}
// len(x)
mode := invalid
var val constant.Value
- switch t := arrayPtrDeref(under(x.typ)).(type) {
+ switch t := arrayPtrDeref(x.typ.Underlying()).(type) {
case *Basic:
if isString(t) && id == _Len {
if x.mode == constant_ {
if mode == invalid {
// avoid error if underlying type is invalid
- if isValid(under(x.typ)) {
+ if isValid(x.typ.Underlying()) {
code := InvalidCap
if id == _Len {
code = InvalidLen
// (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type {
assert(!isTypeParam(typ))
- if t, _ := under(typ).(*Basic); t != nil {
+ if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind {
case Float32:
return Typ[Complex64]
// (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type {
assert(!isTypeParam(typ))
- if t, _ := under(typ).(*Basic); t != nil {
+ if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind {
case Complex64:
return Typ[Float32]
}()
}
- switch u := under(t).(type) {
+ switch u := t.Underlying().(type) {
case *Array:
return hasVarSize(u.elem, seen)
case *Struct:
// otherwise it returns typ.
func arrayPtrDeref(typ Type) Type {
if p, ok := Unalias(typ).(*Pointer); ok {
- if a, _ := under(p.base).(*Array); a != nil {
+ if a, _ := p.base.Underlying().(*Array); a != nil {
return a
}
}
check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T)
break
}
- if t, _ := under(T).(*Interface); t != nil && !isTypeParam(T) {
+ if t, _ := T.Underlying().(*Interface); t != nil && !isTypeParam(T) {
if !t.IsMethodSet() {
check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
break
obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
- if !isValid(under(x.typ)) {
+ if !isValid(x.typ.Underlying()) {
goto Error
}
// x.typ cannot be a type parameter (type
// parameters cannot be constant types).
if isTyped(x.typ) {
- check.representable(x, under(x.typ).(*Basic))
+ check.representable(x, x.typ.Underlying().(*Basic))
return
}
constArg := x.mode == constant_
constConvertibleTo := func(T Type, val *constant.Value) bool {
- switch t, _ := under(T).(*Basic); {
+ switch t, _ := T.Underlying().(*Basic); {
case t == nil:
// nothing to do
case representableConst(x.val, check, t, val):
origT := T
V := Unalias(x.typ)
T = Unalias(T)
- Vu := under(V)
- Tu := under(T)
+ Vu := V.Underlying()
+ Tu := T.Underlying()
Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam)
// and their pointer base types are not type parameters"
if V, ok := V.(*Pointer); ok {
if T, ok := T.(*Pointer); ok {
- if IdenticalIgnoreTags(under(V.base), under(T.base)) && !isTypeParam(V.base) && !isTypeParam(T.base) {
+ if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) && !isTypeParam(V.base) && !isTypeParam(T.base) {
return true
}
}
return false
}
case *Pointer:
- if a, _ := under(a.Elem()).(*Array); a != nil {
+ if a, _ := a.Elem().Underlying().(*Array); a != nil {
if Identical(s.Elem(), a.Elem()) {
if check == nil || check.allowVersion(go1_17) {
return true
}
func isUintptr(typ Type) bool {
- t, _ := under(typ).(*Basic)
+ t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == Uintptr
}
func isUnsafePointer(typ Type) bool {
- t, _ := under(typ).(*Basic)
+ t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == UnsafePointer
}
func isPointer(typ Type) bool {
- _, ok := under(typ).(*Pointer)
+ _, ok := typ.Underlying().(*Pointer)
return ok
}
func isBytesOrRunes(typ Type) bool {
- if s, _ := under(typ).(*Slice); s != nil {
- t, _ := under(s.elem).(*Basic)
+ if s, _ := typ.Underlying().(*Slice); s != nil {
+ t, _ := s.elem.Underlying().(*Basic)
return t != nil && (t.kind == Byte || t.kind == Rune)
}
return false
if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type
// (go.dev/issue/22090)
- if isValid(under(t)) {
+ if isValid(t.Underlying()) {
check.errorf(typ, InvalidConstType, "invalid constant type %s", t)
}
obj.typ = Typ[Invalid]
// If the new type is not final and still untyped, just
// update the recorded type.
if !final && isUntyped(typ) {
- old.typ = under(typ).(*Basic)
+ old.typ = typ.Underlying().(*Basic)
check.untyped[x] = old
return
}
return nil, nil, InvalidUntypedConversion
}
- switch u := under(target).(type) {
+ switch u := target.Underlying().(type) {
case *Basic:
if x.mode == constant_ {
v, code := check.representation(x, u)
// incomparableCause returns a more specific cause why typ is not comparable.
// If there is no more specific cause, the result is "".
func (check *Checker) incomparableCause(typ Type) string {
- switch under(typ).(type) {
+ switch typ.Underlying().(type) {
case *Slice, *Signature, *Map:
return compositeKind(typ) + " can only be compared to nil"
}
// The result is nil if typ is not a signature.
func newTarget(typ Type, desc string) *target {
if typ != nil {
- if sig, _ := under(typ).(*Signature); sig != nil {
+ if sig, _ := typ.Underlying().(*Signature); sig != nil {
return &target{sig, desc}
}
}
check.errorf(x, InvalidAssert, invalidOp+"cannot use type assertion on type parameter value %s", x)
goto Error
}
- if _, ok := under(x.typ).(*Interface); !ok {
+ if _, ok := x.typ.Underlying().(*Interface); !ok {
check.errorf(x, InvalidAssert, invalidOp+"%s is not an interface", x)
goto Error
}
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1."
}
func (s *gcSizes) Sizeof(T Type) int64 {
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Basic:
assert(isTyped(T))
k := t.kind
return false
case value:
- if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
+ if sig, _ := x.typ.Underlying().(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
// function instantiation
return true
}
// ordinary index expression
valid := false
length := int64(-1) // valid if >= 0
- switch typ := under(x.typ).(type) {
+ switch typ := x.typ.Underlying().(type) {
case *Basic:
if isString(typ) {
valid = true
x.typ = typ.elem
case *Pointer:
- if typ, _ := under(typ.base).(*Array); typ != nil {
+ if typ, _ := typ.base.Underlying().(*Array); typ != nil {
valid = true
length = typ.len
x.mode = variable
mode = value
}
case *Pointer:
- if t, _ := under(t.base).(*Array); t != nil {
+ if t, _ := t.base.Underlying().(*Array); t != nil {
l = t.len
e = t.elem
}
// but don't go from untyped string to string.
cu = Typ[String]
if !isTypeParam(x.typ) {
- cu = under(x.typ) // untyped string remains untyped
+ cu = x.typ.Underlying() // untyped string remains untyped
}
}
x.typ = &Slice{elem: u.elem}
case *Pointer:
- if u, _ := under(u.base).(*Array); u != nil {
+ if u, _ := u.base.Underlying().(*Array); u != nil {
valid = true
length = u.len
x.typ = &Slice{elem: u.elem}
if n == 1 {
if debug {
u, _ := commonUnder(tpar, nil)
- assert(under(single.typ) == u)
+ assert(single.typ.Underlying() == u)
}
return single, true
}
// If the provided cause is non-nil, it may be set to an error string
// explaining why V does not implement (or satisfy, for constraints) T.
func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool {
- Vu := under(V)
- Tu := under(T)
+ Vu := V.Underlying()
+ Tu := T.Underlying()
if !isValid(Vu) || !isValid(Tu) {
return true // avoid follow-on errors
}
- if p, _ := Vu.(*Pointer); p != nil && !isValid(under(p.base)) {
+ if p, _ := Vu.(*Pointer); p != nil && !isValid(p.base.Underlying()) {
return true // avoid follow-on errors (see go.dev/issue/49541 for an example)
}
// If V ∉ t.typ but V ∈ ~t.typ then remember this type
// so we can suggest it as an alternative in the error
// message.
- if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) {
+ if alt == nil && !t.tilde && Identical(t.typ, t.typ.Underlying()) {
tt := *t
tt.tilde = true
if tt.includes(V) {
// *typ where typ is an interface (incl. a type parameter) has no methods.
if isPtr {
- if _, ok := under(typ).(*Interface); ok {
+ if _, ok := typ.Underlying().(*Interface); ok {
return
}
}
}
}
- switch t := under(typ).(type) {
+ switch t := typ.Underlying().(type) {
case *Struct:
// look for a matching field and collect embedded types
for i, f := range t.fields {
// The comparator is used to compare signatures.
// If a method is missing and cause is not nil, *cause describes the error.
func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y Type) bool, cause *string) (method *Func, wrongType bool) {
- methods := under(T).(*Interface).typeSet().methods // T must be an interface
+ methods := T.Underlying().(*Interface).typeSet().methods // T must be an interface
if len(methods) == 0 {
return nil, false
}
var m *Func // method on T we're trying to implement
var f *Func // method on V, if found (state is one of ok, wrongName, wrongSig)
- if u, _ := under(V).(*Interface); u != nil {
+ if u, _ := V.Underlying().(*Interface); u != nil {
tset := u.typeSet()
for _, m = range methods {
_, f = tset.LookupMethod(m.pkg, m.name, false)
// hasInvalidEmbeddedFields reports whether T is a struct (or a pointer to a struct) that contains
// (directly or indirectly) embedded fields with invalid types.
func hasInvalidEmbeddedFields(T Type, seen map[*Struct]bool) bool {
- if S, _ := under(derefStructPtr(T)).(*Struct); S != nil && !seen[S] {
+ if S, _ := derefStructPtr(T).Underlying().(*Struct); S != nil && !seen[S] {
if seen == nil {
seen = make(map[*Struct]bool)
}
}
func isInterfacePtr(T Type) bool {
- p, _ := under(T).(*Pointer)
+ p, _ := T.Underlying().(*Pointer)
return p != nil && IsInterface(p.base)
}
// check may be nil.
func (check *Checker) interfacePtrError(T Type) string {
assert(isInterfacePtr(T))
- if p, _ := under(T).(*Pointer); isTypeParam(p.base) {
+ if p, _ := T.Underlying().(*Pointer); isTypeParam(p.base) {
return check.sprintf("type %s is pointer to type parameter, not type parameter", T)
}
return check.sprintf("type %s is pointer to interface, not interface", T)
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
// (named or unnamed) struct and returns its base. Otherwise it returns typ.
func derefStructPtr(typ Type) Type {
- if p, _ := under(typ).(*Pointer); p != nil {
- if _, ok := under(p.base).(*Struct); ok {
+ if p, _ := typ.Underlying().(*Pointer); p != nil {
+ if _, ok := p.base.Underlying().(*Struct); ok {
return p.base
}
}
}
}
- switch t := under(typ).(type) {
+ switch t := typ.Underlying().(type) {
case *Struct:
for i, f := range t.fields {
if fset == nil {
} else {
// TODO(gri) should this be fromRHS for *Named?
// (See discussion in #66559.)
- typ = under(typ)
+ typ = typ.Underlying()
}
}
what := compositeKind(x.typ)
if what == "" {
// x.typ must be basic type
- what = under(x.typ).(*Basic).name
+ what = x.typ.Underlying().(*Basic).name
}
desc += what + " "
}
// ("array", "slice", etc.) or the empty string if typ is not
// composite but a basic type.
func compositeKind(typ Type) string {
- switch under(typ).(type) {
+ switch typ.Underlying().(type) {
case *Basic:
return ""
case *Array:
return true, 0
}
- Vu := under(V)
- Tu := under(T)
+ Vu := V.Underlying()
+ Tu := T.Underlying()
Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam)
func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
func isConstType(t Type) bool { return isBasic(t, IsConstType) }
-// isBasic reports whether under(t) is a basic type with the specified info.
+// isBasic reports whether t.Underlying() is a basic type with the specified info.
// If t is a type parameter the result is false; i.e.,
// isBasic does not look inside a type parameter.
func isBasic(t Type, info BasicInfo) bool {
- u, _ := under(t).(*Basic)
+ u, _ := t.Underlying().(*Basic)
return u != nil && u.info&info != 0
}
func allOrdered(t Type) bool { return allBasic(t, IsOrdered) }
func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
-// allBasic reports whether under(t) is a basic type with the specified info.
+// allBasic reports whether t.Underlying() is a basic type with the specified info.
// If t is a type parameter, the result is true if isBasic(t, info) is true
// for all specific types of the type parameter's type set.
func allBasic(t Type, info BasicInfo) bool {
// IsInterface reports whether t is an interface type.
func IsInterface(t Type) bool {
- _, ok := under(t).(*Interface)
+ _, ok := t.Underlying().(*Interface)
return ok
}
}
seen[T] = true
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Basic:
// assume invalid types to be comparable to avoid follow-up errors
if t.kind == UntypedNil {
// hasNil reports whether type t includes the nil value.
func hasNil(t Type) bool {
- switch u := under(t).(type) {
+ switch u := t.Underlying().(type) {
case *Basic:
return u.kind == UnsafePointer
case *Slice, *Pointer, *Signature, *Map, *Chan:
check.expr(nil, &x, rangeVar)
if isTypes2 && x.mode != invalid && sValue == nil && !check.hasCallOrRecv {
- if t, ok := arrayPtrDeref(under(x.typ)).(*Array); ok {
+ if t, ok := arrayPtrDeref(x.typ.Underlying()).(*Array); ok {
for {
// Put constant info on the thing inside parentheses.
// That's where (*../noder/writer).expr expects it.
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1."
}
func (s *StdSizes) Sizeof(T Type) int64 {
- switch t := under(T).(type) {
+ switch t := T.Underlying().(type) {
case *Basic:
assert(isTyped(T))
k := t.kind
func (conf *Config) offsetof(T Type, index []int) int64 {
var offs int64
for _, i := range index {
- s := under(T).(*Struct)
+ s := T.Underlying().(*Struct)
d := conf.offsetsof(s)[i]
if d < 0 {
return -1
// Because we have a name, typ must be of the form T or *T, where T is the name
// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
// We must delay this check to the end because we don't want to instantiate
- // (via under(t)) a possibly incomplete type.
+ // (via t.Underlying()) a possibly incomplete type.
// for use in the closure below
embeddedTyp := typ
check.later(func() {
t, isPtr := deref(embeddedTyp)
- switch u := under(t).(type) {
+ switch u := t.Underlying().(type) {
case *Basic:
if !isValid(t) {
// error was reported before
// determine constraint interface
var ityp *Interface
- switch u := under(bound).(type) {
+ switch u := bound.Underlying().(type) {
case *Basic:
if !isValid(u) {
// error is reported elsewhere
for _, t := range s.terms {
assert(t.typ != nil)
- // Unalias(x) == under(x) for ~x terms
+ // Unalias(x) == x.Underlying() for ~x terms
u := Unalias(t.typ)
if !t.tilde {
- u = under(u)
+ u = u.Underlying()
}
if debug {
- assert(Identical(u, under(u)))
+ assert(Identical(u, u.Underlying()))
}
if !f(t.typ, u) {
return false
}
var comparable bool
var terms termlist
- switch u := under(typ).(type) {
+ switch u := typ.Underlying().(type) {
case *Interface:
// For now we don't permit type parameters as constraints.
assert(!isTypeParam(typ))
var allTerms termlist
for _, t := range utyp.terms {
var terms termlist
- u := under(t.typ)
+ u := t.typ.Underlying()
if ui, _ := u.(*Interface); ui != nil {
// For now we don't permit type parameters as constraints.
assert(!isTypeParam(t.typ))
if obj == nil {
t.Fatalf("%s: T not found (invalid test case)", body)
}
- T, ok := under(obj.Type()).(*Interface)
+ T, ok := obj.Type().Underlying().(*Interface)
if !ok {
t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj)
}
} else {
// special case:
// append(s, "foo"...) leads to signature func([]byte, string...)
- if t, _ := under(typ).(*Basic); t == nil || t.kind != String {
+ if t, _ := typ.Underlying().(*Basic); t == nil || t.kind != String {
w.error("expected string type")
continue
}
u := t
if x.tilde {
- u = under(u)
+ u = u.Underlying()
}
return Identical(x.typ, u)
}
}
ux := x.typ
if y.tilde {
- ux = under(ux)
+ ux = ux.Underlying()
}
uy := y.typ
if x.tilde {
- uy = under(uy)
+ uy = uy.Underlying()
}
return !Identical(ux, uy)
}
return
}
- // We don't want to call under() or complete interfaces while we are in
+ // We don't want to call typ.Underlying() or complete interfaces while we are in
// the middle of type-checking parameter declarations that might belong
// to interface methods. Delay this check to the end of type-checking.
check.later(func() {
- if t, _ := under(typ).(*Interface); t != nil {
+ if t, _ := typ.Underlying().(*Interface); t != nil {
tset := computeInterfaceTypeSet(check, e.Pos(), t) // TODO(gri) is this the correct position?
if !tset.IsMethodSet() {
if tset.comparable {
check.indent--
var under Type
if T != nil {
- // Calling under() here may lead to endless instantiations.
+ // Calling T.Underlying() here may lead to endless instantiations.
// Test case: type T[P any] *T[P]
under = safeUnderlying(T)
}
import "iter"
-// under returns the true expanded underlying type.
-// If it doesn't exist, the result is Typ[Invalid].
-// under must only be called when a type is known
-// to be fully set up.
-func under(t Type) Type {
- // TODO(markfreeman): Remove this function, it just delegates.
- return t.Underlying()
-}
-
// If typ is a type parameter, underIs returns the result of typ.underIs(f).
-// Otherwise, underIs returns the result of f(under(typ)).
+// Otherwise, underIs returns the result of f(typ.Underlying()).
func underIs(typ Type, f func(Type) bool) bool {
return all(typ, func(_, u Type) bool {
return f(u)
if p, _ := Unalias(t).(*TypeParam); p != nil {
return p.typeset(f)
}
- return f(t, under(t))
+ return f(t, t.Underlying())
}
// typeset is an iterator over the (type/underlying type) pairs of the
// it is a non-type parameter interface. Otherwise it returns nil.
func asInterface(x Type) (i *Interface) {
if _, ok := Unalias(x).(*TypeParam); !ok {
- i, _ = under(x).(*Interface)
+ i, _ = x.Underlying().(*Interface)
}
return i
}
u.set(px, y)
default:
// Neither x nor y are defined types.
- if yc, _ := under(y).(*Chan); yc != nil && yc.dir != SendRecv {
+ if yc, _ := y.Underlying().(*Chan); yc != nil && yc.dir != SendRecv {
// y is a directed channel type: select y.
u.set(px, y)
}
continue
}
- u := under(t.typ)
+ u := t.typ.Underlying()
f, _ := u.(*Interface)
if t.tilde {
if f != nil {