1
0
mirror of https://github.com/golang/go synced 2024-10-01 09:38:36 -06: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:
Gordon Klaus 2014-02-03 11:21:01 -08:00 committed by Robert Griesemer
parent ed1b894ade
commit 3e68d08251
6 changed files with 18 additions and 22 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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)
}
})