diff --git a/src/go/types/NOTES b/src/go/types/NOTES index 55ab4f6552..d9a5c6fc3b 100644 --- a/src/go/types/NOTES +++ b/src/go/types/NOTES @@ -13,6 +13,8 @@ TODO (implementation issues) ---------------------------------------------------------------------------------------------------- KNOWN ISSUES +- type parameter constraints are ignored when checking if a parameterized method implements the + matching method in an interface - iteration over generic variables doesn't report certain channel errors (see TODOs in code) - cannot handle mutually recursive parameterized interfaces using themselves as type bounds example: type B(type P B(P)) interface{ m() } (need to delay all checking after seting up declarations) diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 0bef6014b5..1c940aa5b7 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -104,6 +104,7 @@ var tests = [][]string{ {"testdata/tmp.go2"}, // used for ad-hoc tests - file contents transient {"testdata/typeargs.go2"}, {"testdata/typeparams.go2"}, + {"testdata/mtypeparams.go2"}, {"testdata/typeinst.go2"}, {"testdata/typeinst2.go2"}, {"testdata/issues.go2"}, diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 47441c7ddc..21465b3d12 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -341,7 +341,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := check.newUnifier(true) - u.x.init(mtyp.tparams) + u.x.init(ftyp.tparams) if !u.unify(ftyp, mtyp) { return m, f } @@ -414,7 +414,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, // TODO(gri) is this always correct? what about type bounds? // (Alternative is to rename/subst type parameters and compare.) u := check.newUnifier(true) - u.x.init(mtyp.tparams) + u.x.init(ftyp.tparams) if !u.unify(ftyp, mtyp) { return m, f } diff --git a/src/go/types/testdata/mtypeparams.go2 b/src/go/types/testdata/mtypeparams.go2 new file mode 100644 index 0000000000..6623b2f317 --- /dev/null +++ b/src/go/types/testdata/mtypeparams.go2 @@ -0,0 +1,48 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// If types.Config.AcceptMethodTypeParams is set, +// the type checker accepts methods that have their +// own type parameter list. + +package p + +type S struct{} + +func (S) m(type T)(v T) + +type I interface { + m(type T)(v T) +} + +type J interface { + m(type T)(v T) +} + +var _ I = S{} +var _ I = J(nil) + +type C interface{ n() } + +type Sc struct{} + +func (Sc) m(type T C)(v T) + +type Ic interface { + m(type T C)(v T) +} + +type Jc interface { + m(type T C)(v T) +} + +var _ Ic = Sc{} +var _ Ic = Jc(nil) + +// TODO(gri) These should fail because the constraints don't match. +var _ I = Sc{} +var _ I = Jc(nil) + +var _ Ic = S{} +var _ Ic = J(nil) diff --git a/src/go/types/testdata/typeparams.go2 b/src/go/types/testdata/typeparams.go2 index d0ab4a87cb..ed845352cc 100644 --- a/src/go/types/testdata/typeparams.go2 +++ b/src/go/types/testdata/typeparams.go2 @@ -218,7 +218,7 @@ func init(/* ERROR func init must have no type parameters */ type P)() {} type T struct {} func (T) m1() {} -// Experimental: We allow method type parameters. +// The type checker accepts method type parameters if configured accordingly. func (T) m2(type)() {} func (T) m3(type P)() {}