diff --git a/go/types/lookup.go b/go/types/lookup.go index a293895f..dc2eaf14 100644 --- a/go/types/lookup.go +++ b/go/types/lookup.go @@ -225,22 +225,18 @@ func consolidateMultiples(list []embeddedType) []embeddedType { // is missing or simply has the wrong type. // func MissingMethod(typ Type, T *Interface) (method *Func, wrongType bool) { - // an interface type implements T if it has no methods with conflicting signatures - // Note: This is stronger than the current spec. Should the spec require this? - // fast path for common case if T.NumMethods() == 0 { return } - // An interface type implements T if it has at least the methods of T. + // The dynamic type of a value stored in an interface may implement T, + // but only if all the shared interface methods have matching signatures. + // Note: This is stronger than the current spec. Should the spec require this? if ityp, _ := typ.Underlying().(*Interface); ityp != nil { for _, m := range T.methods { _, obj := lookupMethod(ityp.methods, m.pkg, m.name) - if obj == nil { - return m, false - } - if !IsIdentical(obj.Type(), m.typ) { + if obj != nil && !IsIdentical(obj.Type(), m.typ) { return m, true } } diff --git a/go/types/stdlib_test.go b/go/types/stdlib_test.go index d9c20680..70e6f7b6 100644 --- a/go/types/stdlib_test.go +++ b/go/types/stdlib_test.go @@ -108,6 +108,7 @@ func TestStdfixed(t *testing.T) { "bug050.go", "bug088.go", "bug106.go", // TODO(gri) parser loses comments when bailing out early "bug222.go", "bug282.go", "bug306.go", // TODO(gri) parser loses comments when bailing out early "bug136.go", "bug179.go", "bug344.go", // TODO(gri) implement missing label checks + "bug251.go", // TODO(gri) incorrect cycle checks for interface types "bug165.go", // TODO(gri) isComparable not working for incomplete struct type "bug176.go", // TODO(gri) composite literal array index must be non-negative constant "bug200.go", // TODO(gri) complete duplicate checking in expr switches diff --git a/go/types/testdata/conversions.src b/go/types/testdata/conversions.src index 82af6314..7cf36f0d 100644 --- a/go/types/testdata/conversions.src +++ b/go/types/testdata/conversions.src @@ -44,12 +44,19 @@ func interface_conversions() { type I2 interface{ m1() - m2() + m2(x int) + } + + type I3 interface{ + m1() + m2() int } var e E var i1 I1 var i2 I2 + var i3 I3 + _ = E(0) _ = E(nil) _ = E(e) @@ -59,10 +66,18 @@ func interface_conversions() { _ = I1 /* ERROR "cannot convert" */ (0) _ = I1(nil) _ = I1(i1) - _ = I1 /* ERROR "cannot convert" */ (e) + _ = I1(e) _ = I1(i2) - _ = I2 /* ERROR "cannot convert" */ (i1) + _ = I2(nil) + _ = I2(i1) + _ = I2(i2) + _ = I2 /* ERROR "cannot convert" */ (i3) + + _ = I3(nil) + _ = I3(i1) + _ = I3 /* ERROR "cannot convert" */ (i2) + _ = I3(i3) // TODO(gri) add more tests, improve error message } \ No newline at end of file diff --git a/go/types/testdata/stmt0.src b/go/types/testdata/stmt0.src index c183b890..d148caaf 100644 --- a/go/types/testdata/stmt0.src +++ b/go/types/testdata/stmt0.src @@ -298,6 +298,19 @@ func typeswitch1() { } } +// Test correct typeswitch against interface types. +type A interface { a() } +type B interface { b() } +type C interface { a(int) } + +func typeswitch2() { + switch A(nil).(type) { + case A: + case B: + case C /* ERROR "cannot have dynamic type" */: + } +} + func rangeloops() { var ( x int