mirror of
https://github.com/golang/go
synced 2024-11-14 20:00:31 -07:00
go/types, types2: implement underIs, coreType, coreString via typeset iterator
Remove remaining underIs methods and call underIs function instead. Change-Id: Ic98430d3a56b85f6f4b35c4508c4c67dafbfa3f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/614240 Reviewed-by: Tim King <taking@google.com> Reviewed-by: Robert Griesemer <gri@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
d39b366841
commit
681751a1fe
@ -184,8 +184,8 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
if !isTypeParam(x.typ) {
|
||||
break
|
||||
}
|
||||
if t.typeSet().underIs(func(t Type) bool {
|
||||
switch t := arrayPtrDeref(t).(type) {
|
||||
if underIs(x.typ, func(u Type) bool {
|
||||
switch t := arrayPtrDeref(u).(type) {
|
||||
case *Basic:
|
||||
if isString(t) && id == _Len {
|
||||
return true
|
||||
|
@ -56,7 +56,7 @@ func (check *Checker) conversion(x *operand, T Type) {
|
||||
// If T's type set is empty, or if it doesn't
|
||||
// have specific types, constant x cannot be
|
||||
// converted.
|
||||
ok = Unalias(T).(*TypeParam).underIs(func(u Type) bool {
|
||||
ok = underIs(T, func(u Type) bool {
|
||||
// u is nil if there are no specific type terms
|
||||
if u == nil {
|
||||
cause = check.sprintf("%s does not contain specific types", T)
|
||||
|
@ -434,7 +434,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
|
||||
}
|
||||
case *Interface:
|
||||
if isTypeParam(target) {
|
||||
if !u.typeSet().underIs(func(u Type) bool {
|
||||
if !underIs(target, func(u Type) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
|
||||
var key, elem Type // key != nil: we must have all maps
|
||||
mode := variable // non-maps result mode
|
||||
// TODO(gri) factor out closure and use it for non-typeparam cases as well
|
||||
if typ.typeSet().underIs(func(u Type) bool {
|
||||
if underIs(x.typ, func(u Type) bool {
|
||||
l := int64(-1) // valid if >= 0
|
||||
var k, e Type // k is only set for maps
|
||||
switch t := u.(type) {
|
||||
|
@ -211,7 +211,7 @@ func hasNil(t Type) bool {
|
||||
case *Slice, *Pointer, *Signature, *Map, *Chan:
|
||||
return true
|
||||
case *Interface:
|
||||
return !isTypeParam(t) || u.typeSet().underIs(func(u Type) bool {
|
||||
return !isTypeParam(t) || underIs(t, func(u Type) bool {
|
||||
return u != nil && hasNil(u)
|
||||
})
|
||||
}
|
||||
|
@ -155,13 +155,6 @@ func (t *TypeParam) is(f func(*term) bool) bool {
|
||||
return t.iface().typeSet().is(f)
|
||||
}
|
||||
|
||||
// underIs calls f with the underlying types of the specific type terms
|
||||
// of t's constraint and reports whether all calls to f returned true.
|
||||
// If there are no specific terms, underIs returns the result of f(nil).
|
||||
func (t *TypeParam) underIs(f func(Type) bool) bool {
|
||||
return t.iface().typeSet().underIs(f)
|
||||
}
|
||||
|
||||
// typeset is an iterator over the (type/underlying type) pairs of the
|
||||
// specific type terms of t's constraint.
|
||||
// If there are no specific terms, typeset calls yield with (nil, nil).
|
||||
|
@ -145,30 +145,6 @@ func (s *_TypeSet) is(f func(*term) bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// underIs calls f with the underlying types of the specific type terms
|
||||
// of s and reports whether all calls to f returned true. If there are
|
||||
// no specific terms, underIs returns the result of f(nil).
|
||||
func (s *_TypeSet) underIs(f func(Type) bool) bool {
|
||||
if !s.hasTerms() {
|
||||
return f(nil)
|
||||
}
|
||||
for _, t := range s.terms {
|
||||
assert(t.typ != nil)
|
||||
// Unalias(x) == under(x) for ~x terms
|
||||
u := Unalias(t.typ)
|
||||
if !t.tilde {
|
||||
u = under(u)
|
||||
}
|
||||
if debug {
|
||||
assert(Identical(u, under(u)))
|
||||
}
|
||||
if !f(u) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// topTypeSet may be used as type set for the empty interface.
|
||||
var topTypeSet = _TypeSet{terms: allTermlist}
|
||||
|
||||
|
@ -18,11 +18,12 @@ func under(t Type) Type {
|
||||
// If typ is a type parameter, underIs returns the result of typ.underIs(f).
|
||||
// Otherwise, underIs returns the result of f(under(typ)).
|
||||
func underIs(typ Type, f func(Type) bool) bool {
|
||||
typ = Unalias(typ)
|
||||
if tpar, _ := typ.(*TypeParam); tpar != nil {
|
||||
return tpar.underIs(f)
|
||||
}
|
||||
return f(under(typ))
|
||||
var ok bool
|
||||
typeset(typ, func(_, u Type) bool {
|
||||
ok = f(u)
|
||||
return ok
|
||||
})
|
||||
return ok
|
||||
}
|
||||
|
||||
// typeset is an iterator over the (type/underlying type) pairs of the
|
||||
@ -46,45 +47,38 @@ func typeset(t Type, yield func(t, u Type) bool) {
|
||||
// identical element types), the single underlying type is the restricted
|
||||
// channel type if the restrictions are always the same, or nil otherwise.
|
||||
func coreType(t Type) Type {
|
||||
t = Unalias(t)
|
||||
tpar, _ := t.(*TypeParam)
|
||||
if tpar == nil {
|
||||
return under(t)
|
||||
}
|
||||
|
||||
var su Type
|
||||
if tpar.underIs(func(u Type) bool {
|
||||
typeset(t, func(_, u Type) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
if su != nil {
|
||||
u = match(su, u)
|
||||
if u == nil {
|
||||
su = nil
|
||||
return false
|
||||
}
|
||||
}
|
||||
// su == nil || match(su, u) != nil
|
||||
su = u
|
||||
return true
|
||||
}) {
|
||||
})
|
||||
return su
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// coreString is like coreType but also considers []byte
|
||||
// and strings as identical. In this case, if successful and we saw
|
||||
// a string, the result is of type (possibly untyped) string.
|
||||
func coreString(t Type) Type {
|
||||
t = Unalias(t)
|
||||
tpar, _ := t.(*TypeParam)
|
||||
if tpar == nil {
|
||||
return under(t) // string or untyped string
|
||||
// This explicit case is needed because otherwise the
|
||||
// result would be string if t is an untyped string.
|
||||
if !isTypeParam(t) {
|
||||
return under(t) // untyped string remains untyped
|
||||
}
|
||||
|
||||
var su Type
|
||||
hasString := false
|
||||
if tpar.underIs(func(u Type) bool {
|
||||
typeset(t, func(_, u Type) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
@ -95,20 +89,20 @@ func coreString(t Type) Type {
|
||||
if su != nil {
|
||||
u = match(su, u)
|
||||
if u == nil {
|
||||
su = nil
|
||||
hasString = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
// su == nil || match(su, u) != nil
|
||||
su = u
|
||||
return true
|
||||
}) {
|
||||
})
|
||||
if hasString {
|
||||
return Typ[String]
|
||||
}
|
||||
return su
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If x and y are identical, match returns x.
|
||||
// If x and y are identical channels but for their direction
|
||||
|
@ -187,8 +187,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
if !isTypeParam(x.typ) {
|
||||
break
|
||||
}
|
||||
if t.typeSet().underIs(func(t Type) bool {
|
||||
switch t := arrayPtrDeref(t).(type) {
|
||||
if underIs(x.typ, func(u Type) bool {
|
||||
switch t := arrayPtrDeref(u).(type) {
|
||||
case *Basic:
|
||||
if isString(t) && id == _Len {
|
||||
return true
|
||||
|
@ -59,7 +59,7 @@ func (check *Checker) conversion(x *operand, T Type) {
|
||||
// If T's type set is empty, or if it doesn't
|
||||
// have specific types, constant x cannot be
|
||||
// converted.
|
||||
ok = Unalias(T).(*TypeParam).underIs(func(u Type) bool {
|
||||
ok = underIs(T, func(u Type) bool {
|
||||
// u is nil if there are no specific type terms
|
||||
if u == nil {
|
||||
cause = check.sprintf("%s does not contain specific types", T)
|
||||
|
@ -410,7 +410,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
|
||||
}
|
||||
case *Interface:
|
||||
if isTypeParam(target) {
|
||||
if !u.typeSet().underIs(func(u Type) bool {
|
||||
if !underIs(target, func(u Type) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
|
||||
var key, elem Type // key != nil: we must have all maps
|
||||
mode := variable // non-maps result mode
|
||||
// TODO(gri) factor out closure and use it for non-typeparam cases as well
|
||||
if typ.typeSet().underIs(func(u Type) bool {
|
||||
if underIs(x.typ, func(u Type) bool {
|
||||
l := int64(-1) // valid if >= 0
|
||||
var k, e Type // k is only set for maps
|
||||
switch t := u.(type) {
|
||||
|
@ -214,7 +214,7 @@ func hasNil(t Type) bool {
|
||||
case *Slice, *Pointer, *Signature, *Map, *Chan:
|
||||
return true
|
||||
case *Interface:
|
||||
return !isTypeParam(t) || u.typeSet().underIs(func(u Type) bool {
|
||||
return !isTypeParam(t) || underIs(t, func(u Type) bool {
|
||||
return u != nil && hasNil(u)
|
||||
})
|
||||
}
|
||||
|
@ -158,13 +158,6 @@ func (t *TypeParam) is(f func(*term) bool) bool {
|
||||
return t.iface().typeSet().is(f)
|
||||
}
|
||||
|
||||
// underIs calls f with the underlying types of the specific type terms
|
||||
// of t's constraint and reports whether all calls to f returned true.
|
||||
// If there are no specific terms, underIs returns the result of f(nil).
|
||||
func (t *TypeParam) underIs(f func(Type) bool) bool {
|
||||
return t.iface().typeSet().underIs(f)
|
||||
}
|
||||
|
||||
// typeset is an iterator over the (type/underlying type) pairs of the
|
||||
// specific type terms of t's constraint.
|
||||
// If there are no specific terms, typeset calls yield with (nil, nil).
|
||||
|
@ -148,30 +148,6 @@ func (s *_TypeSet) is(f func(*term) bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// underIs calls f with the underlying types of the specific type terms
|
||||
// of s and reports whether all calls to f returned true. If there are
|
||||
// no specific terms, underIs returns the result of f(nil).
|
||||
func (s *_TypeSet) underIs(f func(Type) bool) bool {
|
||||
if !s.hasTerms() {
|
||||
return f(nil)
|
||||
}
|
||||
for _, t := range s.terms {
|
||||
assert(t.typ != nil)
|
||||
// Unalias(x) == under(x) for ~x terms
|
||||
u := Unalias(t.typ)
|
||||
if !t.tilde {
|
||||
u = under(u)
|
||||
}
|
||||
if debug {
|
||||
assert(Identical(u, under(u)))
|
||||
}
|
||||
if !f(u) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// topTypeSet may be used as type set for the empty interface.
|
||||
var topTypeSet = _TypeSet{terms: allTermlist}
|
||||
|
||||
|
@ -21,11 +21,12 @@ func under(t Type) Type {
|
||||
// If typ is a type parameter, underIs returns the result of typ.underIs(f).
|
||||
// Otherwise, underIs returns the result of f(under(typ)).
|
||||
func underIs(typ Type, f func(Type) bool) bool {
|
||||
typ = Unalias(typ)
|
||||
if tpar, _ := typ.(*TypeParam); tpar != nil {
|
||||
return tpar.underIs(f)
|
||||
}
|
||||
return f(under(typ))
|
||||
var ok bool
|
||||
typeset(typ, func(_, u Type) bool {
|
||||
ok = f(u)
|
||||
return ok
|
||||
})
|
||||
return ok
|
||||
}
|
||||
|
||||
// typeset is an iterator over the (type/underlying type) pairs of the
|
||||
@ -49,45 +50,38 @@ func typeset(t Type, yield func(t, u Type) bool) {
|
||||
// identical element types), the single underlying type is the restricted
|
||||
// channel type if the restrictions are always the same, or nil otherwise.
|
||||
func coreType(t Type) Type {
|
||||
t = Unalias(t)
|
||||
tpar, _ := t.(*TypeParam)
|
||||
if tpar == nil {
|
||||
return under(t)
|
||||
}
|
||||
|
||||
var su Type
|
||||
if tpar.underIs(func(u Type) bool {
|
||||
typeset(t, func(_, u Type) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
if su != nil {
|
||||
u = match(su, u)
|
||||
if u == nil {
|
||||
su = nil
|
||||
return false
|
||||
}
|
||||
}
|
||||
// su == nil || match(su, u) != nil
|
||||
su = u
|
||||
return true
|
||||
}) {
|
||||
})
|
||||
return su
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// coreString is like coreType but also considers []byte
|
||||
// and strings as identical. In this case, if successful and we saw
|
||||
// a string, the result is of type (possibly untyped) string.
|
||||
func coreString(t Type) Type {
|
||||
t = Unalias(t)
|
||||
tpar, _ := t.(*TypeParam)
|
||||
if tpar == nil {
|
||||
return under(t) // string or untyped string
|
||||
// This explicit case is needed because otherwise the
|
||||
// result would be string if t is an untyped string.
|
||||
if !isTypeParam(t) {
|
||||
return under(t) // untyped string remains untyped
|
||||
}
|
||||
|
||||
var su Type
|
||||
hasString := false
|
||||
if tpar.underIs(func(u Type) bool {
|
||||
typeset(t, func(_, u Type) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
@ -98,20 +92,20 @@ func coreString(t Type) Type {
|
||||
if su != nil {
|
||||
u = match(su, u)
|
||||
if u == nil {
|
||||
su = nil
|
||||
hasString = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
// su == nil || match(su, u) != nil
|
||||
su = u
|
||||
return true
|
||||
}) {
|
||||
})
|
||||
if hasString {
|
||||
return Typ[String]
|
||||
}
|
||||
return su
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If x and y are identical, match returns x.
|
||||
// If x and y are identical channels but for their direction
|
||||
|
Loading…
Reference in New Issue
Block a user