mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
parent
1099436f1b
commit
0c14000f87
55 changed files with 171 additions and 189 deletions
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue