mirror of
https://github.com/golang/go
synced 2024-11-19 00:54:42 -07:00
go.tools/go/types: export Comparable and Assertable, simplify Implements
The "static bool" parameter to Implements was confusing; typically we think about interface implementation and type assertion as separate but related concepts, but here they were merged. LGTM=gri R=gri CC=golang-codereviews https://golang.org/cl/58540044
This commit is contained in:
parent
ed1b894ade
commit
3e68d08251
@ -226,6 +226,12 @@ func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, i
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
// Assertable reports whether a value of type V can be asserted to have type T.
|
||||
func Assertable(V *Interface, T Type) bool {
|
||||
f, _ := MissingMethod(T, V, false)
|
||||
return f == nil
|
||||
}
|
||||
|
||||
// AssignableTo reports whether a value of type V is assignable to a variable of type T.
|
||||
func AssignableTo(V, T Type) bool {
|
||||
x := operand{mode: value, typ: V}
|
||||
@ -238,19 +244,8 @@ func ConvertibleTo(V, T Type) bool {
|
||||
return x.convertibleTo(nil, T) // config not needed for non-constant x
|
||||
}
|
||||
|
||||
// Implements reports whether a value of type V implements T, as follows:
|
||||
//
|
||||
// 1) For non-interface types V, or if static is set, V implements T if all
|
||||
// methods of T are present in V. Informally, this reports whether V is a
|
||||
// subtype of T.
|
||||
//
|
||||
// 2) For interface types V, and if static is not set, V implements T if all
|
||||
// methods of T which are also present in V have matching types. Informally,
|
||||
// this indicates whether a type assertion x.(T) where x is of type V would
|
||||
// be legal (the concrete dynamic type of x may implement T even if V does
|
||||
// not statically implement it).
|
||||
//
|
||||
func Implements(V Type, T *Interface, static bool) bool {
|
||||
f, _ := MissingMethod(V, T, static)
|
||||
// Implements reports whether type V implements interface T.
|
||||
func Implements(V Type, T *Interface) bool {
|
||||
f, _ := MissingMethod(V, T, true)
|
||||
return f == nil
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ func (check *checker) comparison(x, y *operand, op token.Token) {
|
||||
switch op {
|
||||
case token.EQL, token.NEQ:
|
||||
// spec: "The equality operators == and != apply to operands that are comparable."
|
||||
defined = isComparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
|
||||
defined = Comparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
|
||||
case token.LSS, token.LEQ, token.GTR, token.GEQ:
|
||||
// spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
|
||||
defined = isOrdered(x.typ)
|
||||
|
@ -242,7 +242,7 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
|
||||
// methods of T are present in V. Otherwise (V is an interface and static
|
||||
// is not set), MissingMethod only checks that methods of T which are also
|
||||
// present in V have matching types (e.g., for a type assertion x.(T) where
|
||||
// x is of interface type typ).
|
||||
// x is of interface type V).
|
||||
//
|
||||
func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
|
||||
// fast path for common case
|
||||
|
@ -217,7 +217,7 @@ func (x *operand) assignableTo(conf *Config, T Type) bool {
|
||||
// T is an interface type and x implements T
|
||||
// (Do this check first as it might succeed early.)
|
||||
if Ti, ok := Tu.(*Interface); ok {
|
||||
if m, _ := MissingMethod(x.typ, Ti, true); m == nil {
|
||||
if Implements(x.typ, Ti) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,9 @@ func isInterface(typ Type) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func isComparable(typ Type) bool {
|
||||
switch t := typ.Underlying().(type) {
|
||||
// Comparable reports whether values of type T are comparable.
|
||||
func Comparable(T Type) bool {
|
||||
switch t := T.Underlying().(type) {
|
||||
case *Basic:
|
||||
// assume invalid types to be comparable
|
||||
// to avoid follow-up errors
|
||||
@ -86,13 +87,13 @@ func isComparable(typ Type) bool {
|
||||
return true
|
||||
case *Struct:
|
||||
for _, f := range t.fields {
|
||||
if !isComparable(f.typ) {
|
||||
if !Comparable(f.typ) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case *Array:
|
||||
return isComparable(t.elem)
|
||||
return Comparable(t.elem)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ func (check *checker) typInternal(e ast.Expr, def *Named, path []*TypeName) Type
|
||||
// Delay this check because it requires fully setup types;
|
||||
// it is safe to continue in any case (was issue 6667).
|
||||
check.delay(func() {
|
||||
if !isComparable(typ.key) {
|
||||
if !Comparable(typ.key) {
|
||||
check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user