]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: method recv type parameter count must match base type parameter...
authorRobert Griesemer <gri@golang.org>
Thu, 24 Feb 2022 05:43:06 +0000 (21:43 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 24 Feb 2022 22:11:25 +0000 (22:11 +0000)
Check receiver type parameter count when type checking the method
signature and report a suitable error (don't rely on delayed
instantiation and possibly constraint type inference).

While at it, simplify blank name recoding and type bound rewriting.

Stop-gap measure to avoid crashes in the compiler.

Fixes #51339.
For #51343.

Change-Id: Idbe2d32d69b66573ca973339f8924b349d2bc9cc
Reviewed-on: https://go-review.googlesource.com/c/go/+/387836
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/signature.go
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 [new file with mode: 0644]
src/go/types/assignments.go
src/go/types/signature.go
src/go/types/testdata/fixedbugs/issue51339.go2 [new file with mode: 0644]

index 936930f0b108327d4c5e9f4c438544507377237a..d88b03748fa02578caee8662e8d2dc50f4cb3f02 100644 (file)
@@ -294,15 +294,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
        return "(" + strings.Join(res, ", ") + ")"
 }
 
-func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
-       measure := func(x int, unit string) string {
-               s := fmt.Sprintf("%d %s", x, unit)
-               if x != 1 {
-                       s += "s"
-               }
-               return s
+func measure(x int, unit string) string {
+       if x != 1 {
+               unit += "s"
        }
+       return fmt.Sprintf("%d %s", x, unit)
+}
 
+func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
        vars := measure(nvars, "variable")
        vals := measure(nvals, "value")
        rhs0 := rhs[0]
index c87fab749c6ccfaea54b36e09a37e7d3a54afb81..76e588254d754a37009a523b334ee998e6c3f7c5 100644 (file)
@@ -116,11 +116,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
                        // lookup in the scope.
                        for i, p := range rparams {
                                if p.Value == "_" {
-                                       tpar := sig.rparams.At(i)
                                        if check.recvTParamMap == nil {
                                                check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
                                        }
-                                       check.recvTParamMap[p] = tpar
+                                       check.recvTParamMap[p] = tparams[i]
                                }
                        }
                        // determine receiver type to get its type parameters
@@ -136,22 +135,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
                                }
                        }
                        // provide type parameter bounds
-                       // - only do this if we have the right number (otherwise an error is reported elsewhere)
-                       if sig.RecvTypeParams().Len() == len(recvTParams) {
-                               // We have a list of *TypeNames but we need a list of Types.
-                               list := make([]Type, sig.RecvTypeParams().Len())
-                               for i, t := range sig.RecvTypeParams().list() {
-                                       list[i] = t
-                                       check.mono.recordCanon(t, recvTParams[i])
-                               }
-                               smap := makeSubstMap(recvTParams, list)
-                               for i, tpar := range sig.RecvTypeParams().list() {
-                                       bound := recvTParams[i].bound
-                                       // bound is (possibly) parameterized in the context of the
-                                       // receiver type declaration. Substitute parameters for the
-                                       // current context.
-                                       tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
+                       if len(tparams) == len(recvTParams) {
+                               smap := makeRenameMap(recvTParams, tparams)
+                               for i, tpar := range tparams {
+                                       recvTPar := recvTParams[i]
+                                       check.mono.recordCanon(tpar, recvTPar)
+                                       // recvTPar.bound is (possibly) parameterized in the context of the
+                                       // receiver type declaration. Substitute parameters for the current
+                                       // context.
+                                       tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
                                }
+                       } else if len(tparams) < len(recvTParams) {
+                               // Reporting an error here is a stop-gap measure to avoid crashes in the
+                               // compiler when a type parameter/argument cannot be inferred later. It
+                               // may lead to follow-on errors (see issues #51339, #51343).
+                               // TODO(gri) find a better solution
+                               got := measure(len(tparams), "type parameter")
+                               check.errorf(recvPar, "got %s, but receiver base type declares %d", got, len(recvTParams))
                        }
                }
        }
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
new file mode 100644 (file)
index 0000000..40706ec
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2022 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.
+
+// This file is tested when running "go test -run Manual"
+// without source arguments. Use for one-off debugging.
+
+package p
+
+type T[P any, B *P] struct{}
+
+func (T /* ERROR cannot use generic type */ ) m0() {}
+func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ [_]) m1() {}
+func (T[_, _]) m2() {}
+// TODO(gri) this error is unfortunate (issue #51343)
+func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
index f75b8b6f6b65cd244c0f74d640109b7adf287188..f5e22c2f675eef5c110d42fd3906e1fcf31ef460 100644 (file)
@@ -290,15 +290,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
        return "(" + strings.Join(res, ", ") + ")"
 }
 
-func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
-       measure := func(x int, unit string) string {
-               s := fmt.Sprintf("%d %s", x, unit)
-               if x != 1 {
-                       s += "s"
-               }
-               return s
+func measure(x int, unit string) string {
+       if x != 1 {
+               unit += "s"
        }
+       return fmt.Sprintf("%d %s", x, unit)
+}
 
+func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
        vars := measure(nvars, "variable")
        vals := measure(nvals, "value")
        rhs0 := rhs[0]
index 8f89e931fbb61d5b8583f30200a7f91678ba746c..f17451626801cf44a8db7c2f420b49385cbee167 100644 (file)
@@ -112,7 +112,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                // - the receiver specification acts as local declaration for its type parameters, which may be blank
                _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true)
                if len(rparams) > 0 {
-                       sig.rparams = bindTParams(check.declareTypeParams(nil, rparams))
+                       tparams := check.declareTypeParams(nil, rparams)
+                       sig.rparams = bindTParams(tparams)
                        // Blank identifiers don't get declared, so naive type-checking of the
                        // receiver type expression would fail in Checker.collectParams below,
                        // when Checker.ident cannot resolve the _ to a type.
@@ -122,11 +123,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                        // lookup in the scope.
                        for i, p := range rparams {
                                if p.Name == "_" {
-                                       tpar := sig.rparams.At(i)
                                        if check.recvTParamMap == nil {
                                                check.recvTParamMap = make(map[*ast.Ident]*TypeParam)
                                        }
-                                       check.recvTParamMap[p] = tpar
+                                       check.recvTParamMap[p] = tparams[i]
                                }
                        }
                        // determine receiver type to get its type parameters
@@ -142,22 +142,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                                }
                        }
                        // provide type parameter bounds
-                       // - only do this if we have the right number (otherwise an error is reported elsewhere)
-                       if sig.RecvTypeParams().Len() == len(recvTParams) {
-                               // We have a list of *TypeNames but we need a list of Types.
-                               list := make([]Type, sig.RecvTypeParams().Len())
-                               for i, t := range sig.RecvTypeParams().list() {
-                                       list[i] = t
-                                       check.mono.recordCanon(t, recvTParams[i])
-                               }
-                               smap := makeSubstMap(recvTParams, list)
-                               for i, tpar := range sig.RecvTypeParams().list() {
-                                       bound := recvTParams[i].bound
-                                       // bound is (possibly) parameterized in the context of the
-                                       // receiver type declaration. Substitute parameters for the
-                                       // current context.
-                                       tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
+                       if len(tparams) == len(recvTParams) {
+                               smap := makeRenameMap(recvTParams, tparams)
+                               for i, tpar := range tparams {
+                                       recvTPar := recvTParams[i]
+                                       check.mono.recordCanon(tpar, recvTPar)
+                                       // recvTPar.bound is (possibly) parameterized in the context of the
+                                       // receiver type declaration. Substitute parameters for the current
+                                       // context.
+                                       tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
                                }
+                       } else if len(tparams) < len(recvTParams) {
+                               // Reporting an error here is a stop-gap measure to avoid crashes in the
+                               // compiler when a type parameter/argument cannot be inferred later. It
+                               // may lead to follow-on errors (see issues #51339, #51343).
+                               // TODO(gri) find a better solution
+                               got := measure(len(tparams), "type parameter")
+                               check.errorf(recvPar, _BadRecv, "got %s, but receiver base type declares %d", got, len(recvTParams))
                        }
                }
        }
diff --git a/src/go/types/testdata/fixedbugs/issue51339.go2 b/src/go/types/testdata/fixedbugs/issue51339.go2
new file mode 100644 (file)
index 0000000..6803c44
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2022 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.
+
+// This file is tested when running "go test -run Manual"
+// without source arguments. Use for one-off debugging.
+
+package p
+
+type T[P any, B *P] struct{}
+
+func (T /* ERROR cannot use generic type */ ) m0() {}
+func (/* ERROR got 1 type parameter, but receiver base type declares 2 */ T[_]) m1() {}
+func (T[_, _]) m2() {}
+// TODO(gri) this error is unfortunate (issue #51343)
+func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}