go/types, types2: remove under(Type) in favor of Type.Underlying()

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>
This commit is contained in:
Mark Freeman 2025-10-16 11:08:13 -04:00 committed by Gopher Robot
parent 1099436f1b
commit 0c14000f87
55 changed files with 171 additions and 189 deletions

View file

@ -91,7 +91,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
// x.typ is typed // x.typ is typed
// A generic (non-instantiated) function value cannot be assigned to a variable. // 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) check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
x.mode = invalid x.mode = invalid
return return
@ -261,7 +261,7 @@ func (check *Checker) assignVar(lhs, rhs syntax.Expr, x *operand, context string
var target *target var target *target
// avoid calling ExprString if not needed // avoid calling ExprString if not needed
if T != nil { if T != nil {
if _, ok := under(T).(*Signature); ok { if _, ok := T.Underlying().(*Signature); ok {
target = newTarget(T, ExprString(lhs)) target = newTarget(T, ExprString(lhs))
} }
} }

View file

@ -144,7 +144,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// len(x) // len(x)
mode := invalid mode := invalid
var val constant.Value var val constant.Value
switch t := arrayPtrDeref(under(x.typ)).(type) { switch t := arrayPtrDeref(x.typ.Underlying()).(type) {
case *Basic: case *Basic:
if isString(t) && id == _Len { if isString(t) && id == _Len {
if x.mode == constant_ { if x.mode == constant_ {
@ -203,7 +203,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
if mode == invalid { if mode == invalid {
// avoid error if underlying type is invalid // avoid error if underlying type is invalid
if isValid(under(x.typ)) { if isValid(x.typ.Underlying()) {
code := InvalidCap code := InvalidCap
if id == _Len { if id == _Len {
code = InvalidLen code = InvalidLen
@ -322,7 +322,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// (applyTypeFunc never calls f with a type parameter) // (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type { f := func(typ Type) Type {
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
if t, _ := under(typ).(*Basic); t != nil { if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind { switch t.kind {
case Float32: case Float32:
return Typ[Complex64] return Typ[Complex64]
@ -472,7 +472,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// (applyTypeFunc never calls f with a type parameter) // (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type { f := func(typ Type) Type {
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
if t, _ := under(typ).(*Basic); t != nil { if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind { switch t.kind {
case Complex64: case Complex64:
return Typ[Float32] return Typ[Float32]
@ -1020,7 +1020,7 @@ func hasVarSize(t Type, seen map[*Named]bool) (varSized bool) {
}() }()
} }
switch u := under(t).(type) { switch u := t.Underlying().(type) {
case *Array: case *Array:
return hasVarSize(u.elem, seen) return hasVarSize(u.elem, seen)
case *Struct: case *Struct:
@ -1112,7 +1112,7 @@ func makeSig(res Type, args ...Type) *Signature {
// otherwise it returns typ. // otherwise it returns typ.
func arrayPtrDeref(typ Type) Type { func arrayPtrDeref(typ Type) Type {
if p, ok := Unalias(typ).(*Pointer); ok { 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 return a
} }
} }

View file

@ -205,7 +205,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
case 1: case 1:
check.expr(nil, x, call.ArgList[0]) check.expr(nil, x, call.ArgList[0])
if x.mode != invalid { 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() { if !t.IsMethodSet() {
check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T) check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
break break
@ -812,7 +812,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false) obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false)
if obj == nil { if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541). // 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 goto Error
} }

View file

@ -33,7 +33,7 @@ func (check *Checker) overflow(x *operand, opPos syntax.Pos) {
// x.typ cannot be a type parameter (type // x.typ cannot be a type parameter (type
// parameters cannot be constant types). // parameters cannot be constant types).
if isTyped(x.typ) { if isTyped(x.typ) {
check.representable(x, under(x.typ).(*Basic)) check.representable(x, x.typ.Underlying().(*Basic))
return return
} }

View file

@ -18,7 +18,7 @@ func (check *Checker) conversion(x *operand, T Type) {
constArg := x.mode == constant_ constArg := x.mode == constant_
constConvertibleTo := func(T Type, val *constant.Value) bool { constConvertibleTo := func(T Type, val *constant.Value) bool {
switch t, _ := under(T).(*Basic); { switch t, _ := T.Underlying().(*Basic); {
case t == nil: case t == nil:
// nothing to do // nothing to do
case representableConst(x.val, check, t, val): case representableConst(x.val, check, t, val):
@ -142,8 +142,8 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
origT := T origT := T
V := Unalias(x.typ) V := Unalias(x.typ)
T = Unalias(T) T = Unalias(T)
Vu := under(V) Vu := V.Underlying()
Tu := under(T) Tu := T.Underlying()
Vp, _ := V.(*TypeParam) Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam) Tp, _ := T.(*TypeParam)
@ -158,7 +158,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
// and their pointer base types are not type parameters" // and their pointer base types are not type parameters"
if V, ok := V.(*Pointer); ok { if V, ok := V.(*Pointer); ok {
if T, ok := T.(*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 true
} }
} }
@ -211,7 +211,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
return false return false
} }
case *Pointer: 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 Identical(s.Elem(), a.Elem()) {
if check == nil || check.allowVersion(go1_17) { if check == nil || check.allowVersion(go1_17) {
return true return true
@ -292,23 +292,23 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
} }
func isUintptr(typ Type) bool { func isUintptr(typ Type) bool {
t, _ := under(typ).(*Basic) t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == Uintptr return t != nil && t.kind == Uintptr
} }
func isUnsafePointer(typ Type) bool { func isUnsafePointer(typ Type) bool {
t, _ := under(typ).(*Basic) t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == UnsafePointer return t != nil && t.kind == UnsafePointer
} }
func isPointer(typ Type) bool { func isPointer(typ Type) bool {
_, ok := under(typ).(*Pointer) _, ok := typ.Underlying().(*Pointer)
return ok return ok
} }
func isBytesOrRunes(typ Type) bool { func isBytesOrRunes(typ Type) bool {
if s, _ := under(typ).(*Slice); s != nil { if s, _ := typ.Underlying().(*Slice); s != nil {
t, _ := under(s.elem).(*Basic) t, _ := s.elem.Underlying().(*Basic)
return t != nil && (t.kind == Byte || t.kind == Rune) return t != nil && (t.kind == Byte || t.kind == Rune)
} }
return false return false

View file

@ -391,7 +391,7 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited boo
if !isConstType(t) { if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type // don't report an error if the type is an invalid C (defined) type
// (go.dev/issue/22090) // (go.dev/issue/22090)
if isValid(under(t)) { if isValid(t.Underlying()) {
check.errorf(typ, InvalidConstType, "invalid constant type %s", t) check.errorf(typ, InvalidConstType, "invalid constant type %s", t)
} }
obj.typ = Typ[Invalid] obj.typ = Typ[Invalid]

View file

@ -361,7 +361,7 @@ func (check *Checker) updateExprType(x syntax.Expr, typ Type, final bool) {
// If the new type is not final and still untyped, just // If the new type is not final and still untyped, just
// update the recorded type. // update the recorded type.
if !final && isUntyped(typ) { if !final && isUntyped(typ) {
old.typ = under(typ).(*Basic) old.typ = typ.Underlying().(*Basic)
check.untyped[x] = old check.untyped[x] = old
return return
} }
@ -431,7 +431,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
return nil, nil, InvalidUntypedConversion return nil, nil, InvalidUntypedConversion
} }
switch u := under(target).(type) { switch u := target.Underlying().(type) {
case *Basic: case *Basic:
if x.mode == constant_ { if x.mode == constant_ {
v, code := check.representation(x, u) v, code := check.representation(x, u)
@ -616,7 +616,7 @@ Error:
// incomparableCause returns a more specific cause why typ is not comparable. // incomparableCause returns a more specific cause why typ is not comparable.
// If there is no more specific cause, the result is "". // If there is no more specific cause, the result is "".
func (check *Checker) incomparableCause(typ Type) string { func (check *Checker) incomparableCause(typ Type) string {
switch under(typ).(type) { switch typ.Underlying().(type) {
case *Slice, *Signature, *Map: case *Slice, *Signature, *Map:
return compositeKind(typ) + " can only be compared to nil" return compositeKind(typ) + " can only be compared to nil"
} }
@ -963,7 +963,7 @@ type target struct {
// The result is nil if typ is not a signature. // The result is nil if typ is not a signature.
func newTarget(typ Type, desc string) *target { func newTarget(typ Type, desc string) *target {
if typ != nil { if typ != nil {
if sig, _ := under(typ).(*Signature); sig != nil { if sig, _ := typ.Underlying().(*Signature); sig != nil {
return &target{sig, desc} return &target{sig, desc}
} }
} }
@ -1112,7 +1112,7 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty
check.errorf(x, InvalidAssert, invalidOp+"cannot use type assertion on type parameter value %s", x) check.errorf(x, InvalidAssert, invalidOp+"cannot use type assertion on type parameter value %s", x)
goto Error 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) check.errorf(x, InvalidAssert, invalidOp+"%s is not an interface", x)
goto Error goto Error
} }

View file

@ -16,7 +16,7 @@ func (s *gcSizes) Alignof(T Type) (result int64) {
// For arrays and structs, alignment is defined in terms // For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively. // of alignment of the elements and fields, respectively.
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Array: case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x) // spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1." // is the same as unsafe.Alignof(x[0]), but at least 1."
@ -96,7 +96,7 @@ func (s *gcSizes) Offsetsof(fields []*Var) []int64 {
} }
func (s *gcSizes) Sizeof(T Type) int64 { func (s *gcSizes) Sizeof(T Type) int64 {
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Basic: case *Basic:
assert(isTyped(T)) assert(isTyped(T))
k := t.kind k := t.kind

View file

@ -35,7 +35,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
return false return false
case value: 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 // function instantiation
return true return true
} }
@ -50,7 +50,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
// ordinary index expression // ordinary index expression
valid := false valid := false
length := int64(-1) // valid if >= 0 length := int64(-1) // valid if >= 0
switch typ := under(x.typ).(type) { switch typ := x.typ.Underlying().(type) {
case *Basic: case *Basic:
if isString(typ) { if isString(typ) {
valid = true valid = true
@ -73,7 +73,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
x.typ = typ.elem x.typ = typ.elem
case *Pointer: case *Pointer:
if typ, _ := under(typ.base).(*Array); typ != nil { if typ, _ := typ.base.Underlying().(*Array); typ != nil {
valid = true valid = true
length = typ.len length = typ.len
x.mode = variable x.mode = variable
@ -124,7 +124,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
mode = value mode = value
} }
case *Pointer: case *Pointer:
if t, _ := under(t.base).(*Array); t != nil { if t, _ := t.base.Underlying().(*Array); t != nil {
l = t.len l = t.len
e = t.elem e = t.elem
} }
@ -247,7 +247,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
// but don't go from untyped string to string. // but don't go from untyped string to string.
cu = Typ[String] cu = Typ[String]
if !isTypeParam(x.typ) { if !isTypeParam(x.typ) {
cu = under(x.typ) // untyped string remains untyped cu = x.typ.Underlying() // untyped string remains untyped
} }
} }
@ -292,7 +292,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
x.typ = &Slice{elem: u.elem} x.typ = &Slice{elem: u.elem}
case *Pointer: case *Pointer:
if u, _ := under(u.base).(*Array); u != nil { if u, _ := u.base.Underlying().(*Array); u != nil {
valid = true valid = true
length = u.len length = u.len
x.typ = &Slice{elem: u.elem} x.typ = &Slice{elem: u.elem}

View file

@ -668,7 +668,7 @@ func coreTerm(tpar *TypeParam) (*term, bool) {
if n == 1 { if n == 1 {
if debug { if debug {
u, _ := commonUnder(tpar, nil) u, _ := commonUnder(tpar, nil)
assert(under(single.typ) == u) assert(single.typ.Underlying() == u)
} }
return single, true return single, true
} }

View file

@ -226,12 +226,12 @@ func (check *Checker) verify(pos syntax.Pos, tparams []*TypeParam, targs []Type,
// If the provided cause is non-nil, it may be set to an error string // 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. // explaining why V does not implement (or satisfy, for constraints) T.
func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool { func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool {
Vu := under(V) Vu := V.Underlying()
Tu := under(T) Tu := T.Underlying()
if !isValid(Vu) || !isValid(Tu) { if !isValid(Vu) || !isValid(Tu) {
return true // avoid follow-on errors 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) return true // avoid follow-on errors (see go.dev/issue/49541 for an example)
} }
@ -339,7 +339,7 @@ func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool
// If V ∉ t.typ but V ∈ ~t.typ then remember this type // If V ∉ t.typ but V ∈ ~t.typ then remember this type
// so we can suggest it as an alternative in the error // so we can suggest it as an alternative in the error
// message. // 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 := *t
tt.tilde = true tt.tilde = true
if tt.includes(V) { if tt.includes(V) {

View file

@ -152,7 +152,7 @@ func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string
// *typ where typ is an interface (incl. a type parameter) has no methods. // *typ where typ is an interface (incl. a type parameter) has no methods.
if isPtr { if isPtr {
if _, ok := under(typ).(*Interface); ok { if _, ok := typ.Underlying().(*Interface); ok {
return return
} }
} }
@ -202,7 +202,7 @@ func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string
} }
} }
switch t := under(typ).(type) { switch t := typ.Underlying().(type) {
case *Struct: case *Struct:
// look for a matching field and collect embedded types // look for a matching field and collect embedded types
for i, f := range t.fields { for i, f := range t.fields {
@ -373,7 +373,7 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
// The comparator is used to compare signatures. // The comparator is used to compare signatures.
// If a method is missing and cause is not nil, *cause describes the error. // 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) { 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 { if len(methods) == 0 {
return nil, false return nil, false
} }
@ -393,7 +393,7 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
var m *Func // method on T we're trying to implement 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) 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() tset := u.typeSet()
for _, m = range methods { for _, m = range methods {
_, f = tset.LookupMethod(m.pkg, m.name, false) _, f = tset.LookupMethod(m.pkg, m.name, false)
@ -534,7 +534,7 @@ func (check *Checker) hasAllMethods(V, T Type, static bool, equivalent func(x, y
// hasInvalidEmbeddedFields reports whether T is a struct (or a pointer to a struct) that contains // hasInvalidEmbeddedFields reports whether T is a struct (or a pointer to a struct) that contains
// (directly or indirectly) embedded fields with invalid types. // (directly or indirectly) embedded fields with invalid types.
func hasInvalidEmbeddedFields(T Type, seen map[*Struct]bool) bool { 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 { if seen == nil {
seen = make(map[*Struct]bool) seen = make(map[*Struct]bool)
} }
@ -549,14 +549,14 @@ func hasInvalidEmbeddedFields(T Type, seen map[*Struct]bool) bool {
} }
func isInterfacePtr(T Type) bool { func isInterfacePtr(T Type) bool {
p, _ := under(T).(*Pointer) p, _ := T.Underlying().(*Pointer)
return p != nil && IsInterface(p.base) return p != nil && IsInterface(p.base)
} }
// check may be nil. // check may be nil.
func (check *Checker) interfacePtrError(T Type) string { func (check *Checker) interfacePtrError(T Type) string {
assert(isInterfacePtr(T)) 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 type parameter, not type parameter", T)
} }
return check.sprintf("type %s is pointer to interface, not interface", T) return check.sprintf("type %s is pointer to interface, not interface", T)
@ -629,8 +629,8 @@ func deref(typ Type) (Type, bool) {
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a // 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. // (named or unnamed) struct and returns its base. Otherwise it returns typ.
func derefStructPtr(typ Type) Type { func derefStructPtr(typ Type) Type {
if p, _ := under(typ).(*Pointer); p != nil { if p, _ := typ.Underlying().(*Pointer); p != nil {
if _, ok := under(p.base).(*Struct); ok { if _, ok := p.base.Underlying().(*Struct); ok {
return p.base return p.base
} }
} }

View file

@ -639,7 +639,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
} else { } else {
// TODO(gri) should this be fromRHS for *Named? // TODO(gri) should this be fromRHS for *Named?
// (See discussion in #66559.) // (See discussion in #66559.)
typ = under(typ) typ = typ.Underlying()
} }
} }

View file

@ -194,7 +194,7 @@ func operandString(x *operand, qf Qualifier) string {
what := compositeKind(x.typ) what := compositeKind(x.typ)
if what == "" { if what == "" {
// x.typ must be basic type // x.typ must be basic type
what = under(x.typ).(*Basic).name what = x.typ.Underlying().(*Basic).name
} }
desc += what + " " desc += what + " "
} }
@ -229,7 +229,7 @@ func operandString(x *operand, qf Qualifier) string {
// ("array", "slice", etc.) or the empty string if typ is not // ("array", "slice", etc.) or the empty string if typ is not
// composite but a basic type. // composite but a basic type.
func compositeKind(typ Type) string { func compositeKind(typ Type) string {
switch under(typ).(type) { switch typ.Underlying().(type) {
case *Basic: case *Basic:
return "" return ""
case *Array: case *Array:
@ -319,8 +319,8 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod
return true, 0 return true, 0
} }
Vu := under(V) Vu := V.Underlying()
Tu := under(T) Tu := T.Underlying()
Vp, _ := V.(*TypeParam) Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam) Tp, _ := T.(*TypeParam)

View file

@ -28,11 +28,11 @@ func isString(t Type) bool { return isBasic(t, IsString) }
func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) } func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
func isConstType(t Type) bool { return isBasic(t, IsConstType) } 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., // If t is a type parameter the result is false; i.e.,
// isBasic does not look inside a type parameter. // isBasic does not look inside a type parameter.
func isBasic(t Type, info BasicInfo) bool { func isBasic(t Type, info BasicInfo) bool {
u, _ := under(t).(*Basic) u, _ := t.Underlying().(*Basic)
return u != nil && u.info&info != 0 return u != nil && u.info&info != 0
} }
@ -48,7 +48,7 @@ func allString(t Type) bool { return allBasic(t, IsString) }
func allOrdered(t Type) bool { return allBasic(t, IsOrdered) } func allOrdered(t Type) bool { return allBasic(t, IsOrdered) }
func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) } 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 // 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. // for all specific types of the type parameter's type set.
func allBasic(t Type, info BasicInfo) bool { func allBasic(t Type, info BasicInfo) bool {
@ -107,7 +107,7 @@ func isUntypedNumeric(t Type) bool {
// IsInterface reports whether t is an interface type. // IsInterface reports whether t is an interface type.
func IsInterface(t Type) bool { func IsInterface(t Type) bool {
_, ok := under(t).(*Interface) _, ok := t.Underlying().(*Interface)
return ok return ok
} }
@ -163,7 +163,7 @@ func comparableType(T Type, dynamic bool, seen map[Type]bool) *typeError {
} }
seen[T] = true seen[T] = true
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Basic: case *Basic:
// assume invalid types to be comparable to avoid follow-up errors // assume invalid types to be comparable to avoid follow-up errors
if t.kind == UntypedNil { if t.kind == UntypedNil {
@ -206,7 +206,7 @@ func comparableType(T Type, dynamic bool, seen map[Type]bool) *typeError {
// hasNil reports whether type t includes the nil value. // hasNil reports whether type t includes the nil value.
func hasNil(t Type) bool { func hasNil(t Type) bool {
switch u := under(t).(type) { switch u := t.Underlying().(type) {
case *Basic: case *Basic:
return u.kind == UnsafePointer return u.kind == UnsafePointer
case *Slice, *Pointer, *Signature, *Map, *Chan: case *Slice, *Pointer, *Signature, *Map, *Chan:

View file

@ -35,7 +35,7 @@ func (check *Checker) rangeStmt(inner stmtContext, rangeStmt *syntax.ForStmt, no
check.expr(nil, &x, rangeVar) check.expr(nil, &x, rangeVar)
if isTypes2 && x.mode != invalid && sValue == nil && !check.hasCallOrRecv { 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 { for {
// Put constant info on the thing inside parentheses. // Put constant info on the thing inside parentheses.
// That's where (*../noder/writer).expr expects it. // That's where (*../noder/writer).expr expects it.

View file

@ -54,7 +54,7 @@ func (s *StdSizes) Alignof(T Type) (result int64) {
// For arrays and structs, alignment is defined in terms // For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively. // of alignment of the elements and fields, respectively.
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Array: case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x) // spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1." // is the same as unsafe.Alignof(x[0]), but at least 1."
@ -162,7 +162,7 @@ var basicSizes = [...]byte{
} }
func (s *StdSizes) Sizeof(T Type) int64 { func (s *StdSizes) Sizeof(T Type) int64 {
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Basic: case *Basic:
assert(isTyped(T)) assert(isTyped(T))
k := t.kind k := t.kind
@ -307,7 +307,7 @@ func (conf *Config) offsetsof(T *Struct) []int64 {
func (conf *Config) offsetof(T Type, index []int) int64 { func (conf *Config) offsetof(T Type, index []int) int64 {
var offs int64 var offs int64
for _, i := range index { for _, i := range index {
s := under(T).(*Struct) s := T.Underlying().(*Struct)
d := conf.offsetsof(s)[i] d := conf.offsetsof(s)[i]
if d < 0 { if d < 0 {
return -1 return -1

View file

@ -141,12 +141,12 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
// Because we have a name, typ must be of the form T or *T, where T is the name // 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. // 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 // 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 embeddedTyp := typ // for closure below
embeddedPos := pos embeddedPos := pos
check.later(func() { check.later(func() {
t, isPtr := deref(embeddedTyp) t, isPtr := deref(embeddedTyp)
switch u := under(t).(type) { switch u := t.Underlying().(type) {
case *Basic: case *Basic:
if !isValid(t) { if !isValid(t) {
// error was reported before // error was reported before

View file

@ -113,7 +113,7 @@ func (t *TypeParam) iface() *Interface {
// determine constraint interface // determine constraint interface
var ityp *Interface var ityp *Interface
switch u := under(bound).(type) { switch u := bound.Underlying().(type) {
case *Basic: case *Basic:
if !isValid(u) { if !isValid(u) {
// error is reported elsewhere // error is reported elsewhere

View file

@ -114,13 +114,13 @@ func (s *_TypeSet) all(f func(t, u Type) bool) bool {
for _, t := range s.terms { for _, t := range s.terms {
assert(t.typ != nil) assert(t.typ != nil)
// Unalias(x) == under(x) for ~x terms // Unalias(x) == x.Underlying() for ~x terms
u := Unalias(t.typ) u := Unalias(t.typ)
if !t.tilde { if !t.tilde {
u = under(u) u = u.Underlying()
} }
if debug { if debug {
assert(Identical(u, under(u))) assert(Identical(u, u.Underlying()))
} }
if !f(t.typ, u) { if !f(t.typ, u) {
return false return false
@ -264,7 +264,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
} }
var comparable bool var comparable bool
var terms termlist var terms termlist
switch u := under(typ).(type) { switch u := typ.Underlying().(type) {
case *Interface: case *Interface:
// For now we don't permit type parameters as constraints. // For now we don't permit type parameters as constraints.
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
@ -380,7 +380,7 @@ func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos syn
var allTerms termlist var allTerms termlist
for _, t := range utyp.terms { for _, t := range utyp.terms {
var terms termlist var terms termlist
u := under(t.typ) u := t.typ.Underlying()
if ui, _ := u.(*Interface); ui != nil { if ui, _ := u.(*Interface); ui != nil {
// For now we don't permit type parameters as constraints. // For now we don't permit type parameters as constraints.
assert(!isTypeParam(t.typ)) assert(!isTypeParam(t.typ))

View file

@ -64,7 +64,7 @@ func TestTypeSetString(t *testing.T) {
if obj == nil { if obj == nil {
t.Fatalf("%s: T not found (invalid test case)", body) t.Fatalf("%s: T not found (invalid test case)", body)
} }
T, ok := under(obj.Type()).(*Interface) T, ok := obj.Type().Underlying().(*Interface)
if !ok { if !ok {
t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj) t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj)
} }

View file

@ -455,7 +455,7 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
} else { } else {
// special case: // special case:
// append(s, "foo"...) leads to signature func([]byte, string...) // 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") w.error("expected string type")
continue continue
} }

View file

@ -115,7 +115,7 @@ func (x *term) includes(t Type) bool {
u := t u := t
if x.tilde { if x.tilde {
u = under(u) u = u.Underlying()
} }
return Identical(x.typ, u) return Identical(x.typ, u)
} }
@ -155,11 +155,11 @@ func (x *term) disjoint(y *term) bool {
} }
ux := x.typ ux := x.typ
if y.tilde { if y.tilde {
ux = under(ux) ux = ux.Underlying()
} }
uy := y.typ uy := y.typ
if x.tilde { if x.tilde {
uy = under(uy) uy = uy.Underlying()
} }
return !Identical(ux, uy) return !Identical(ux, uy)
} }

View file

@ -169,11 +169,11 @@ func (check *Checker) validVarType(e syntax.Expr, typ Type) {
return 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 // the middle of type-checking parameter declarations that might belong
// to interface methods. Delay this check to the end of type-checking. // to interface methods. Delay this check to the end of type-checking.
check.later(func() { check.later(func() {
if t, _ := under(typ).(*Interface); t != nil { if t, _ := typ.Underlying().(*Interface); t != nil {
pos := syntax.StartPos(e) pos := syntax.StartPos(e)
tset := computeInterfaceTypeSet(check, pos, t) // TODO(gri) is this the correct position? tset := computeInterfaceTypeSet(check, pos, t) // TODO(gri) is this the correct position?
if !tset.IsMethodSet() { if !tset.IsMethodSet() {
@ -239,7 +239,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) {
check.indent-- check.indent--
var under Type var under Type
if T != nil { 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] // Test case: type T[P any] *T[P]
under = safeUnderlying(T) under = safeUnderlying(T)
} }

View file

@ -6,17 +6,8 @@ package types2
import "iter" 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). // 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 { func underIs(typ Type, f func(Type) bool) bool {
return all(typ, func(_, u Type) bool { return all(typ, func(_, u Type) bool {
return f(u) return f(u)
@ -29,7 +20,7 @@ func all(t Type, f func(t, u Type) bool) bool {
if p, _ := Unalias(t).(*TypeParam); p != nil { if p, _ := Unalias(t).(*TypeParam); p != nil {
return p.typeset(f) 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 // typeset is an iterator over the (type/underlying type) pairs of the

View file

@ -270,7 +270,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
// it is a non-type parameter interface. Otherwise it returns nil. // it is a non-type parameter interface. Otherwise it returns nil.
func asInterface(x Type) (i *Interface) { func asInterface(x Type) (i *Interface) {
if _, ok := Unalias(x).(*TypeParam); !ok { if _, ok := Unalias(x).(*TypeParam); !ok {
i, _ = under(x).(*Interface) i, _ = x.Underlying().(*Interface)
} }
return i return i
} }
@ -430,7 +430,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
u.set(px, y) u.set(px, y)
default: default:
// Neither x nor y are defined types. // 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. // y is a directed channel type: select y.
u.set(px, y) u.set(px, y)
} }

View file

@ -93,7 +93,7 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type {
continue continue
} }
u := under(t.typ) u := t.typ.Underlying()
f, _ := u.(*Interface) f, _ := u.(*Interface)
if t.tilde { if t.tilde {
if f != nil { if f != nil {

View file

@ -94,7 +94,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
// x.typ is typed // x.typ is typed
// A generic (non-instantiated) function value cannot be assigned to a variable. // 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) check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
x.mode = invalid x.mode = invalid
return return
@ -264,7 +264,7 @@ func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand, context string) {
var target *target var target *target
// avoid calling ExprString if not needed // avoid calling ExprString if not needed
if T != nil { if T != nil {
if _, ok := under(T).(*Signature); ok { if _, ok := T.Underlying().(*Signature); ok {
target = newTarget(T, ExprString(lhs)) target = newTarget(T, ExprString(lhs))
} }
} }

View file

@ -147,7 +147,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// len(x) // len(x)
mode := invalid mode := invalid
var val constant.Value var val constant.Value
switch t := arrayPtrDeref(under(x.typ)).(type) { switch t := arrayPtrDeref(x.typ.Underlying()).(type) {
case *Basic: case *Basic:
if isString(t) && id == _Len { if isString(t) && id == _Len {
if x.mode == constant_ { if x.mode == constant_ {
@ -206,7 +206,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
if mode == invalid { if mode == invalid {
// avoid error if underlying type is invalid // avoid error if underlying type is invalid
if isValid(under(x.typ)) { if isValid(x.typ.Underlying()) {
code := InvalidCap code := InvalidCap
if id == _Len { if id == _Len {
code = InvalidLen code = InvalidLen
@ -325,7 +325,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// (applyTypeFunc never calls f with a type parameter) // (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type { f := func(typ Type) Type {
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
if t, _ := under(typ).(*Basic); t != nil { if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind { switch t.kind {
case Float32: case Float32:
return Typ[Complex64] return Typ[Complex64]
@ -475,7 +475,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// (applyTypeFunc never calls f with a type parameter) // (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type { f := func(typ Type) Type {
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
if t, _ := under(typ).(*Basic); t != nil { if t, _ := typ.Underlying().(*Basic); t != nil {
switch t.kind { switch t.kind {
case Complex64: case Complex64:
return Typ[Float32] return Typ[Float32]
@ -1023,7 +1023,7 @@ func hasVarSize(t Type, seen map[*Named]bool) (varSized bool) {
}() }()
} }
switch u := under(t).(type) { switch u := t.Underlying().(type) {
case *Array: case *Array:
return hasVarSize(u.elem, seen) return hasVarSize(u.elem, seen)
case *Struct: case *Struct:
@ -1115,7 +1115,7 @@ func makeSig(res Type, args ...Type) *Signature {
// otherwise it returns typ. // otherwise it returns typ.
func arrayPtrDeref(typ Type) Type { func arrayPtrDeref(typ Type) Type {
if p, ok := Unalias(typ).(*Pointer); ok { 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 return a
} }
} }

View file

@ -211,7 +211,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T) check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T)
break break
} }
if t, _ := under(T).(*Interface); t != nil && !isTypeParam(T) { if t, _ := T.Underlying().(*Interface); t != nil && !isTypeParam(T) {
if !t.IsMethodSet() { if !t.IsMethodSet() {
check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T) check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
break break
@ -815,7 +815,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false) obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false)
if obj == nil { if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541). // 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 goto Error
} }

View file

@ -35,7 +35,7 @@ func (check *Checker) overflow(x *operand, opPos token.Pos) {
// x.typ cannot be a type parameter (type // x.typ cannot be a type parameter (type
// parameters cannot be constant types). // parameters cannot be constant types).
if isTyped(x.typ) { if isTyped(x.typ) {
check.representable(x, under(x.typ).(*Basic)) check.representable(x, x.typ.Underlying().(*Basic))
return return
} }

View file

@ -21,7 +21,7 @@ func (check *Checker) conversion(x *operand, T Type) {
constArg := x.mode == constant_ constArg := x.mode == constant_
constConvertibleTo := func(T Type, val *constant.Value) bool { constConvertibleTo := func(T Type, val *constant.Value) bool {
switch t, _ := under(T).(*Basic); { switch t, _ := T.Underlying().(*Basic); {
case t == nil: case t == nil:
// nothing to do // nothing to do
case representableConst(x.val, check, t, val): case representableConst(x.val, check, t, val):
@ -145,8 +145,8 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
origT := T origT := T
V := Unalias(x.typ) V := Unalias(x.typ)
T = Unalias(T) T = Unalias(T)
Vu := under(V) Vu := V.Underlying()
Tu := under(T) Tu := T.Underlying()
Vp, _ := V.(*TypeParam) Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam) Tp, _ := T.(*TypeParam)
@ -161,7 +161,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
// and their pointer base types are not type parameters" // and their pointer base types are not type parameters"
if V, ok := V.(*Pointer); ok { if V, ok := V.(*Pointer); ok {
if T, ok := T.(*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 true
} }
} }
@ -214,7 +214,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
return false return false
} }
case *Pointer: 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 Identical(s.Elem(), a.Elem()) {
if check == nil || check.allowVersion(go1_17) { if check == nil || check.allowVersion(go1_17) {
return true return true
@ -295,23 +295,23 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
} }
func isUintptr(typ Type) bool { func isUintptr(typ Type) bool {
t, _ := under(typ).(*Basic) t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == Uintptr return t != nil && t.kind == Uintptr
} }
func isUnsafePointer(typ Type) bool { func isUnsafePointer(typ Type) bool {
t, _ := under(typ).(*Basic) t, _ := typ.Underlying().(*Basic)
return t != nil && t.kind == UnsafePointer return t != nil && t.kind == UnsafePointer
} }
func isPointer(typ Type) bool { func isPointer(typ Type) bool {
_, ok := under(typ).(*Pointer) _, ok := typ.Underlying().(*Pointer)
return ok return ok
} }
func isBytesOrRunes(typ Type) bool { func isBytesOrRunes(typ Type) bool {
if s, _ := under(typ).(*Slice); s != nil { if s, _ := typ.Underlying().(*Slice); s != nil {
t, _ := under(s.elem).(*Basic) t, _ := s.elem.Underlying().(*Basic)
return t != nil && (t.kind == Byte || t.kind == Rune) return t != nil && (t.kind == Byte || t.kind == Rune)
} }
return false return false

View file

@ -466,7 +466,7 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr, inherited bool)
if !isConstType(t) { if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type // don't report an error if the type is an invalid C (defined) type
// (go.dev/issue/22090) // (go.dev/issue/22090)
if isValid(under(t)) { if isValid(t.Underlying()) {
check.errorf(typ, InvalidConstType, "invalid constant type %s", t) check.errorf(typ, InvalidConstType, "invalid constant type %s", t)
} }
obj.typ = Typ[Invalid] obj.typ = Typ[Invalid]

View file

@ -336,7 +336,7 @@ func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
// If the new type is not final and still untyped, just // If the new type is not final and still untyped, just
// update the recorded type. // update the recorded type.
if !final && isUntyped(typ) { if !final && isUntyped(typ) {
old.typ = under(typ).(*Basic) old.typ = typ.Underlying().(*Basic)
check.untyped[x] = old check.untyped[x] = old
return return
} }
@ -398,7 +398,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
return nil, nil, InvalidUntypedConversion return nil, nil, InvalidUntypedConversion
} }
switch u := under(target).(type) { switch u := target.Underlying().(type) {
case *Basic: case *Basic:
if x.mode == constant_ { if x.mode == constant_ {
v, code := check.representation(x, u) v, code := check.representation(x, u)
@ -605,7 +605,7 @@ Error:
// incomparableCause returns a more specific cause why typ is not comparable. // incomparableCause returns a more specific cause why typ is not comparable.
// If there is no more specific cause, the result is "". // If there is no more specific cause, the result is "".
func (check *Checker) incomparableCause(typ Type) string { func (check *Checker) incomparableCause(typ Type) string {
switch under(typ).(type) { switch typ.Underlying().(type) {
case *Slice, *Signature, *Map: case *Slice, *Signature, *Map:
return compositeKind(typ) + " can only be compared to nil" return compositeKind(typ) + " can only be compared to nil"
} }
@ -955,7 +955,7 @@ type target struct {
// The result is nil if typ is not a signature. // The result is nil if typ is not a signature.
func newTarget(typ Type, desc string) *target { func newTarget(typ Type, desc string) *target {
if typ != nil { if typ != nil {
if sig, _ := under(typ).(*Signature); sig != nil { if sig, _ := typ.Underlying().(*Signature); sig != nil {
return &target{sig, desc} return &target{sig, desc}
} }
} }
@ -1101,7 +1101,7 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type)
check.errorf(x, InvalidAssert, invalidOp+"cannot use type assertion on type parameter value %s", x) check.errorf(x, InvalidAssert, invalidOp+"cannot use type assertion on type parameter value %s", x)
goto Error 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) check.errorf(x, InvalidAssert, invalidOp+"%s is not an interface", x)
goto Error goto Error
} }

View file

@ -19,7 +19,7 @@ func (s *gcSizes) Alignof(T Type) (result int64) {
// For arrays and structs, alignment is defined in terms // For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively. // of alignment of the elements and fields, respectively.
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Array: case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x) // spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1." // is the same as unsafe.Alignof(x[0]), but at least 1."
@ -99,7 +99,7 @@ func (s *gcSizes) Offsetsof(fields []*Var) []int64 {
} }
func (s *gcSizes) Sizeof(T Type) int64 { func (s *gcSizes) Sizeof(T Type) int64 {
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Basic: case *Basic:
assert(isTyped(T)) assert(isTyped(T))
k := t.kind k := t.kind

View file

@ -36,7 +36,7 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) {
return false return false
case value: 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 // function instantiation
return true return true
} }
@ -51,7 +51,7 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) {
// ordinary index expression // ordinary index expression
valid := false valid := false
length := int64(-1) // valid if >= 0 length := int64(-1) // valid if >= 0
switch typ := under(x.typ).(type) { switch typ := x.typ.Underlying().(type) {
case *Basic: case *Basic:
if isString(typ) { if isString(typ) {
valid = true valid = true
@ -74,7 +74,7 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) {
x.typ = typ.elem x.typ = typ.elem
case *Pointer: case *Pointer:
if typ, _ := under(typ.base).(*Array); typ != nil { if typ, _ := typ.base.Underlying().(*Array); typ != nil {
valid = true valid = true
length = typ.len length = typ.len
x.mode = variable x.mode = variable
@ -125,7 +125,7 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) {
mode = value mode = value
} }
case *Pointer: case *Pointer:
if t, _ := under(t.base).(*Array); t != nil { if t, _ := t.base.Underlying().(*Array); t != nil {
l = t.len l = t.len
e = t.elem e = t.elem
} }
@ -252,7 +252,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
// but don't go from untyped string to string. // but don't go from untyped string to string.
cu = Typ[String] cu = Typ[String]
if !isTypeParam(x.typ) { if !isTypeParam(x.typ) {
cu = under(x.typ) // untyped string remains untyped cu = x.typ.Underlying() // untyped string remains untyped
} }
} }
@ -297,7 +297,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
x.typ = &Slice{elem: u.elem} x.typ = &Slice{elem: u.elem}
case *Pointer: case *Pointer:
if u, _ := under(u.base).(*Array); u != nil { if u, _ := u.base.Underlying().(*Array); u != nil {
valid = true valid = true
length = u.len length = u.len
x.typ = &Slice{elem: u.elem} x.typ = &Slice{elem: u.elem}

View file

@ -671,7 +671,7 @@ func coreTerm(tpar *TypeParam) (*term, bool) {
if n == 1 { if n == 1 {
if debug { if debug {
u, _ := commonUnder(tpar, nil) u, _ := commonUnder(tpar, nil)
assert(under(single.typ) == u) assert(single.typ.Underlying() == u)
} }
return single, true return single, true
} }

View file

@ -229,12 +229,12 @@ func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type,
// If the provided cause is non-nil, it may be set to an error string // 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. // explaining why V does not implement (or satisfy, for constraints) T.
func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool { func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool {
Vu := under(V) Vu := V.Underlying()
Tu := under(T) Tu := T.Underlying()
if !isValid(Vu) || !isValid(Tu) { if !isValid(Vu) || !isValid(Tu) {
return true // avoid follow-on errors 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) return true // avoid follow-on errors (see go.dev/issue/49541 for an example)
} }
@ -342,7 +342,7 @@ func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool
// If V ∉ t.typ but V ∈ ~t.typ then remember this type // If V ∉ t.typ but V ∈ ~t.typ then remember this type
// so we can suggest it as an alternative in the error // so we can suggest it as an alternative in the error
// message. // 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 := *t
tt.tilde = true tt.tilde = true
if tt.includes(V) { if tt.includes(V) {

View file

@ -155,7 +155,7 @@ func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string
// *typ where typ is an interface (incl. a type parameter) has no methods. // *typ where typ is an interface (incl. a type parameter) has no methods.
if isPtr { if isPtr {
if _, ok := under(typ).(*Interface); ok { if _, ok := typ.Underlying().(*Interface); ok {
return return
} }
} }
@ -205,7 +205,7 @@ func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string
} }
} }
switch t := under(typ).(type) { switch t := typ.Underlying().(type) {
case *Struct: case *Struct:
// look for a matching field and collect embedded types // look for a matching field and collect embedded types
for i, f := range t.fields { for i, f := range t.fields {
@ -376,7 +376,7 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
// The comparator is used to compare signatures. // The comparator is used to compare signatures.
// If a method is missing and cause is not nil, *cause describes the error. // 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) { 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 { if len(methods) == 0 {
return nil, false return nil, false
} }
@ -396,7 +396,7 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
var m *Func // method on T we're trying to implement 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) 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() tset := u.typeSet()
for _, m = range methods { for _, m = range methods {
_, f = tset.LookupMethod(m.pkg, m.name, false) _, f = tset.LookupMethod(m.pkg, m.name, false)
@ -537,7 +537,7 @@ func (check *Checker) hasAllMethods(V, T Type, static bool, equivalent func(x, y
// hasInvalidEmbeddedFields reports whether T is a struct (or a pointer to a struct) that contains // hasInvalidEmbeddedFields reports whether T is a struct (or a pointer to a struct) that contains
// (directly or indirectly) embedded fields with invalid types. // (directly or indirectly) embedded fields with invalid types.
func hasInvalidEmbeddedFields(T Type, seen map[*Struct]bool) bool { 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 { if seen == nil {
seen = make(map[*Struct]bool) seen = make(map[*Struct]bool)
} }
@ -552,14 +552,14 @@ func hasInvalidEmbeddedFields(T Type, seen map[*Struct]bool) bool {
} }
func isInterfacePtr(T Type) bool { func isInterfacePtr(T Type) bool {
p, _ := under(T).(*Pointer) p, _ := T.Underlying().(*Pointer)
return p != nil && IsInterface(p.base) return p != nil && IsInterface(p.base)
} }
// check may be nil. // check may be nil.
func (check *Checker) interfacePtrError(T Type) string { func (check *Checker) interfacePtrError(T Type) string {
assert(isInterfacePtr(T)) 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 type parameter, not type parameter", T)
} }
return check.sprintf("type %s is pointer to interface, not interface", T) return check.sprintf("type %s is pointer to interface, not interface", T)
@ -632,8 +632,8 @@ func deref(typ Type) (Type, bool) {
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a // 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. // (named or unnamed) struct and returns its base. Otherwise it returns typ.
func derefStructPtr(typ Type) Type { func derefStructPtr(typ Type) Type {
if p, _ := under(typ).(*Pointer); p != nil { if p, _ := typ.Underlying().(*Pointer); p != nil {
if _, ok := under(p.base).(*Struct); ok { if _, ok := p.base.Underlying().(*Struct); ok {
return p.base return p.base
} }
} }

View file

@ -133,7 +133,7 @@ func NewMethodSet(T Type) *MethodSet {
} }
} }
switch t := under(typ).(type) { switch t := typ.Underlying().(type) {
case *Struct: case *Struct:
for i, f := range t.fields { for i, f := range t.fields {
if fset == nil { if fset == nil {

View file

@ -642,7 +642,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
} else { } else {
// TODO(gri) should this be fromRHS for *Named? // TODO(gri) should this be fromRHS for *Named?
// (See discussion in #66559.) // (See discussion in #66559.)
typ = under(typ) typ = typ.Underlying()
} }
} }

View file

@ -198,7 +198,7 @@ func operandString(x *operand, qf Qualifier) string {
what := compositeKind(x.typ) what := compositeKind(x.typ)
if what == "" { if what == "" {
// x.typ must be basic type // x.typ must be basic type
what = under(x.typ).(*Basic).name what = x.typ.Underlying().(*Basic).name
} }
desc += what + " " desc += what + " "
} }
@ -233,7 +233,7 @@ func operandString(x *operand, qf Qualifier) string {
// ("array", "slice", etc.) or the empty string if typ is not // ("array", "slice", etc.) or the empty string if typ is not
// composite but a basic type. // composite but a basic type.
func compositeKind(typ Type) string { func compositeKind(typ Type) string {
switch under(typ).(type) { switch typ.Underlying().(type) {
case *Basic: case *Basic:
return "" return ""
case *Array: case *Array:
@ -323,8 +323,8 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod
return true, 0 return true, 0
} }
Vu := under(V) Vu := V.Underlying()
Tu := under(T) Tu := T.Underlying()
Vp, _ := V.(*TypeParam) Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam) Tp, _ := T.(*TypeParam)

View file

@ -31,11 +31,11 @@ func isString(t Type) bool { return isBasic(t, IsString) }
func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) } func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
func isConstType(t Type) bool { return isBasic(t, IsConstType) } 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., // If t is a type parameter the result is false; i.e.,
// isBasic does not look inside a type parameter. // isBasic does not look inside a type parameter.
func isBasic(t Type, info BasicInfo) bool { func isBasic(t Type, info BasicInfo) bool {
u, _ := under(t).(*Basic) u, _ := t.Underlying().(*Basic)
return u != nil && u.info&info != 0 return u != nil && u.info&info != 0
} }
@ -51,7 +51,7 @@ func allString(t Type) bool { return allBasic(t, IsString) }
func allOrdered(t Type) bool { return allBasic(t, IsOrdered) } func allOrdered(t Type) bool { return allBasic(t, IsOrdered) }
func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) } 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 // 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. // for all specific types of the type parameter's type set.
func allBasic(t Type, info BasicInfo) bool { func allBasic(t Type, info BasicInfo) bool {
@ -110,7 +110,7 @@ func isUntypedNumeric(t Type) bool {
// IsInterface reports whether t is an interface type. // IsInterface reports whether t is an interface type.
func IsInterface(t Type) bool { func IsInterface(t Type) bool {
_, ok := under(t).(*Interface) _, ok := t.Underlying().(*Interface)
return ok return ok
} }
@ -166,7 +166,7 @@ func comparableType(T Type, dynamic bool, seen map[Type]bool) *typeError {
} }
seen[T] = true seen[T] = true
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Basic: case *Basic:
// assume invalid types to be comparable to avoid follow-up errors // assume invalid types to be comparable to avoid follow-up errors
if t.kind == UntypedNil { if t.kind == UntypedNil {
@ -209,7 +209,7 @@ func comparableType(T Type, dynamic bool, seen map[Type]bool) *typeError {
// hasNil reports whether type t includes the nil value. // hasNil reports whether type t includes the nil value.
func hasNil(t Type) bool { func hasNil(t Type) bool {
switch u := under(t).(type) { switch u := t.Underlying().(type) {
case *Basic: case *Basic:
return u.kind == UnsafePointer return u.kind == UnsafePointer
case *Slice, *Pointer, *Signature, *Map, *Chan: case *Slice, *Pointer, *Signature, *Map, *Chan:

View file

@ -38,7 +38,7 @@ func (check *Checker) rangeStmt(inner stmtContext, rangeStmt *ast.RangeStmt, noN
check.expr(nil, &x, rangeVar) check.expr(nil, &x, rangeVar)
if isTypes2 && x.mode != invalid && sValue == nil && !check.hasCallOrRecv { 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 { for {
// Put constant info on the thing inside parentheses. // Put constant info on the thing inside parentheses.
// That's where (*../noder/writer).expr expects it. // That's where (*../noder/writer).expr expects it.

View file

@ -57,7 +57,7 @@ func (s *StdSizes) Alignof(T Type) (result int64) {
// For arrays and structs, alignment is defined in terms // For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively. // of alignment of the elements and fields, respectively.
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Array: case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x) // spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1." // is the same as unsafe.Alignof(x[0]), but at least 1."
@ -165,7 +165,7 @@ var basicSizes = [...]byte{
} }
func (s *StdSizes) Sizeof(T Type) int64 { func (s *StdSizes) Sizeof(T Type) int64 {
switch t := under(T).(type) { switch t := T.Underlying().(type) {
case *Basic: case *Basic:
assert(isTyped(T)) assert(isTyped(T))
k := t.kind k := t.kind
@ -310,7 +310,7 @@ func (conf *Config) offsetsof(T *Struct) []int64 {
func (conf *Config) offsetof(T Type, index []int) int64 { func (conf *Config) offsetof(T Type, index []int) int64 {
var offs int64 var offs int64
for _, i := range index { for _, i := range index {
s := under(T).(*Struct) s := T.Underlying().(*Struct)
d := conf.offsetsof(s)[i] d := conf.offsetsof(s)[i]
if d < 0 { if d < 0 {
return -1 return -1

View file

@ -137,7 +137,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
// Because we have a name, typ must be of the form T or *T, where T is the name // 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. // 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 // 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 // for use in the closure below
embeddedTyp := typ embeddedTyp := typ
@ -145,7 +145,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
check.later(func() { check.later(func() {
t, isPtr := deref(embeddedTyp) t, isPtr := deref(embeddedTyp)
switch u := under(t).(type) { switch u := t.Underlying().(type) {
case *Basic: case *Basic:
if !isValid(t) { if !isValid(t) {
// error was reported before // error was reported before

View file

@ -116,7 +116,7 @@ func (t *TypeParam) iface() *Interface {
// determine constraint interface // determine constraint interface
var ityp *Interface var ityp *Interface
switch u := under(bound).(type) { switch u := bound.Underlying().(type) {
case *Basic: case *Basic:
if !isValid(u) { if !isValid(u) {
// error is reported elsewhere // error is reported elsewhere

View file

@ -117,13 +117,13 @@ func (s *_TypeSet) all(f func(t, u Type) bool) bool {
for _, t := range s.terms { for _, t := range s.terms {
assert(t.typ != nil) assert(t.typ != nil)
// Unalias(x) == under(x) for ~x terms // Unalias(x) == x.Underlying() for ~x terms
u := Unalias(t.typ) u := Unalias(t.typ)
if !t.tilde { if !t.tilde {
u = under(u) u = u.Underlying()
} }
if debug { if debug {
assert(Identical(u, under(u))) assert(Identical(u, u.Underlying()))
} }
if !f(t.typ, u) { if !f(t.typ, u) {
return false return false
@ -267,7 +267,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
} }
var comparable bool var comparable bool
var terms termlist var terms termlist
switch u := under(typ).(type) { switch u := typ.Underlying().(type) {
case *Interface: case *Interface:
// For now we don't permit type parameters as constraints. // For now we don't permit type parameters as constraints.
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
@ -383,7 +383,7 @@ func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos tok
var allTerms termlist var allTerms termlist
for _, t := range utyp.terms { for _, t := range utyp.terms {
var terms termlist var terms termlist
u := under(t.typ) u := t.typ.Underlying()
if ui, _ := u.(*Interface); ui != nil { if ui, _ := u.(*Interface); ui != nil {
// For now we don't permit type parameters as constraints. // For now we don't permit type parameters as constraints.
assert(!isTypeParam(t.typ)) assert(!isTypeParam(t.typ))

View file

@ -65,7 +65,7 @@ func TestTypeSetString(t *testing.T) {
if obj == nil { if obj == nil {
t.Fatalf("%s: T not found (invalid test case)", body) t.Fatalf("%s: T not found (invalid test case)", body)
} }
T, ok := under(obj.Type()).(*Interface) T, ok := obj.Type().Underlying().(*Interface)
if !ok { if !ok {
t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj) t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj)
} }

View file

@ -458,7 +458,7 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
} else { } else {
// special case: // special case:
// append(s, "foo"...) leads to signature func([]byte, string...) // 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") w.error("expected string type")
continue continue
} }

View file

@ -118,7 +118,7 @@ func (x *term) includes(t Type) bool {
u := t u := t
if x.tilde { if x.tilde {
u = under(u) u = u.Underlying()
} }
return Identical(x.typ, u) return Identical(x.typ, u)
} }
@ -158,11 +158,11 @@ func (x *term) disjoint(y *term) bool {
} }
ux := x.typ ux := x.typ
if y.tilde { if y.tilde {
ux = under(ux) ux = ux.Underlying()
} }
uy := y.typ uy := y.typ
if x.tilde { if x.tilde {
uy = under(uy) uy = uy.Underlying()
} }
return !Identical(ux, uy) return !Identical(ux, uy)
} }

View file

@ -168,11 +168,11 @@ func (check *Checker) validVarType(e ast.Expr, typ Type) {
return 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 // the middle of type-checking parameter declarations that might belong
// to interface methods. Delay this check to the end of type-checking. // to interface methods. Delay this check to the end of type-checking.
check.later(func() { 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? tset := computeInterfaceTypeSet(check, e.Pos(), t) // TODO(gri) is this the correct position?
if !tset.IsMethodSet() { if !tset.IsMethodSet() {
if tset.comparable { if tset.comparable {
@ -237,7 +237,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *TypeName) (T Type) {
check.indent-- check.indent--
var under Type var under Type
if T != nil { 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] // Test case: type T[P any] *T[P]
under = safeUnderlying(T) under = safeUnderlying(T)
} }

View file

@ -9,17 +9,8 @@ package types
import "iter" 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). // 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 { func underIs(typ Type, f func(Type) bool) bool {
return all(typ, func(_, u Type) bool { return all(typ, func(_, u Type) bool {
return f(u) return f(u)
@ -32,7 +23,7 @@ func all(t Type, f func(t, u Type) bool) bool {
if p, _ := Unalias(t).(*TypeParam); p != nil { if p, _ := Unalias(t).(*TypeParam); p != nil {
return p.typeset(f) 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 // typeset is an iterator over the (type/underlying type) pairs of the

View file

@ -273,7 +273,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
// it is a non-type parameter interface. Otherwise it returns nil. // it is a non-type parameter interface. Otherwise it returns nil.
func asInterface(x Type) (i *Interface) { func asInterface(x Type) (i *Interface) {
if _, ok := Unalias(x).(*TypeParam); !ok { if _, ok := Unalias(x).(*TypeParam); !ok {
i, _ = under(x).(*Interface) i, _ = x.Underlying().(*Interface)
} }
return i return i
} }
@ -433,7 +433,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
u.set(px, y) u.set(px, y)
default: default:
// Neither x nor y are defined types. // 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. // y is a directed channel type: select y.
u.set(px, y) u.set(px, y)
} }

View file

@ -94,7 +94,7 @@ func parseUnion(check *Checker, uexpr ast.Expr) Type {
continue continue
} }
u := under(t.typ) u := t.typ.Underlying()
f, _ := u.(*Interface) f, _ := u.(*Interface)
if t.tilde { if t.tilde {
if f != nil { if f != nil {