From 3e68d0825106de2ffefc17e200b886c539dcf0b7 Mon Sep 17 00:00:00 2001 From: Gordon Klaus Date: Mon, 3 Feb 2014 11:21:01 -0800 Subject: [PATCH] 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 --- go/types/api.go | 23 +++++++++-------------- go/types/expr.go | 2 +- go/types/lookup.go | 2 +- go/types/operand.go | 2 +- go/types/predicates.go | 9 +++++---- go/types/typexpr.go | 2 +- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/go/types/api.go b/go/types/api.go index ba414e7eba3..3e516254631 100644 --- a/go/types/api.go +++ b/go/types/api.go @@ -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 } diff --git a/go/types/expr.go b/go/types/expr.go index be5fe26325b..751eda3fc2c 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -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) diff --git a/go/types/lookup.go b/go/types/lookup.go index 33b87ad2c69..323b6c03dd8 100644 --- a/go/types/lookup.go +++ b/go/types/lookup.go @@ -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 diff --git a/go/types/operand.go b/go/types/operand.go index 74b4a12332f..3d9159fb066 100644 --- a/go/types/operand.go +++ b/go/types/operand.go @@ -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 } } diff --git a/go/types/predicates.go b/go/types/predicates.go index 352e23066e2..4f448e95733 100644 --- a/go/types/predicates.go +++ b/go/types/predicates.go @@ -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 } diff --git a/go/types/typexpr.go b/go/types/typexpr.go index efcd4d38347..9a1d5572b3d 100644 --- a/go/types/typexpr.go +++ b/go/types/typexpr.go @@ -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) } })