]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: slightly reorganize method receiver checking
authorRobert Griesemer <gri@golang.org>
Tue, 18 Jun 2024 17:34:11 +0000 (10:34 -0700)
committerGopher Robot <gobot@golang.org>
Fri, 26 Jul 2024 20:11:48 +0000 (20:11 +0000)
- move receiver checks up, closer to where the receiver is collected
- adjust some comments after verifying against some test cases
- removed some minor discrepancies between the two type checkers

For #51343.

Change-Id: I75b58efbed1e408df89b8d6536e6c6da45740f93
Reviewed-on: https://go-review.googlesource.com/c/go/+/593336
Auto-Submit: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
src/cmd/compile/internal/types2/signature.go
src/go/types/signature.go

index 7a5a2c155f00324fd502dda1af62e3c307bd2c63..5050212e15dced2d62fd6a948efe7ba5a548b29c 100644 (file)
@@ -66,7 +66,7 @@ func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params
 // function. It is ignored when comparing signatures for identity.
 //
 // For an abstract method, Recv returns the enclosing interface either
-// as a *Named or an *Interface. Due to embedding, an interface may
+// as a *[Named] or an *[Interface]. Due to embedding, an interface may
 // contain methods whose receiver type is a different interface.
 func (s *Signature) Recv() *Var { return s.recv }
 
@@ -176,37 +176,37 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
        // Audit to ensure all lookups honor scopePos and simplify.
        scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)")
        scopePos := syntax.EndPos(ftyp) // all parameters' scopes start after the signature
-       var recvList []*Var             // TODO(gri) remove the need for making a list here
-       if recvPar != nil {
-               recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, false, scopePos) // use rewritten receiver type, if any
-       }
-       params, variadic := check.collectParams(scope, ftyp.ParamList, true, scopePos)
-       results, _ := check.collectParams(scope, ftyp.ResultList, false, scopePos)
-       scope.Squash(func(obj, alt Object) {
-               err := check.newError(DuplicateDecl)
-               err.addf(obj, "%s redeclared in this block", obj.Name())
-               err.addAltDecl(alt)
-               err.report()
-       })
 
+       // collect and typecheck receiver, incoming parameters, and results
+       var recv *Var
        if recvPar != nil {
-               // recv parameter list present (may be empty)
                // spec: "The receiver is specified via an extra parameter section preceding the
                // method name. That parameter section must declare a single parameter, the receiver."
-               var recv *Var
+               recvList, _ := check.collectParams(scope, []*syntax.Field{recvPar}, false, scopePos) // use rewritten receiver type, if any
                switch len(recvList) {
                case 0:
-                       // error reported by resolver
-                       recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below
+                       // error reported by parser
+                       recv = NewParam(nopos, nil, "", Typ[Invalid]) // use invalid type so it's ignored by check.later code below
                default:
-                       // more than one receiver
-                       check.error(recvList[len(recvList)-1].Pos(), InvalidRecv, "method must have exactly one receiver")
+                       // error reported by parser
+                       check.error(recvList[len(recvList)-1].Pos(), InvalidRecv, "method has multiple receivers")
                        fallthrough // continue with first receiver
                case 1:
                        recv = recvList[0]
                }
                sig.recv = recv
+       }
+       params, variadic := check.collectParams(scope, ftyp.ParamList, true, scopePos)
+       results, _ := check.collectParams(scope, ftyp.ResultList, false, scopePos)
+
+       scope.Squash(func(obj, alt Object) {
+               err := check.newError(DuplicateDecl)
+               err.addf(obj, "%s redeclared in this block", obj.Name())
+               err.addAltDecl(alt)
+               err.report()
+       })
 
+       if recv != nil {
                // Delay validation of receiver type as it may cause premature expansion
                // of types the receiver type is dependent on (see issues go.dev/issue/51232, go.dev/issue/51233).
                check.later(func() {
index 770edc2b21b801a739f02c6359978bd5fe1d7eb4..9d83dd4fd534030b3c56ff693f63ee10ebb95417 100644 (file)
@@ -96,8 +96,8 @@ func (s *Signature) Results() *Tuple { return s.results }
 // Variadic reports whether the signature s is variadic.
 func (s *Signature) Variadic() bool { return s.variadic }
 
-func (t *Signature) Underlying() Type { return t }
-func (t *Signature) String() string   { return TypeString(t, nil) }
+func (s *Signature) Underlying() Type { return s }
+func (s *Signature) String() string   { return TypeString(s, nil) }
 
 // ----------------------------------------------------------------------------
 // Implementation
@@ -189,25 +189,17 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
        // Audit to ensure all lookups honor scopePos and simplify.
        scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)")
        scopePos := ftyp.End() // all parameters' scopes start after the signature
-       recvList, _ := check.collectParams(scope, recvPar, false, scopePos)
-       params, variadic := check.collectParams(scope, ftyp.Params, true, scopePos)
-       results, _ := check.collectParams(scope, ftyp.Results, false, scopePos)
-       scope.squash(func(obj, alt Object) {
-               err := check.newError(DuplicateDecl)
-               err.addf(obj, "%s redeclared in this block", obj.Name())
-               err.addAltDecl(alt)
-               err.report()
-       })
 
+       // collect and typecheck receiver, incoming parameters, and results
+       var recv *Var
        if recvPar != nil {
-               // recv parameter list present (may be empty)
                // spec: "The receiver is specified via an extra parameter section preceding the
                // method name. That parameter section must declare a single parameter, the receiver."
-               var recv *Var
+               recvList, _ := check.collectParams(scope, recvPar, false, scopePos) // use rewritten receiver type, if any
                switch len(recvList) {
                case 0:
                        // error reported by resolver
-                       recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below
+                       recv = NewParam(nopos, nil, "", Typ[Invalid]) // use invalid type so it's ignored by check.later code below
                default:
                        // more than one receiver
                        check.error(recvList[len(recvList)-1], InvalidRecv, "method has multiple receivers")
@@ -216,7 +208,18 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                        recv = recvList[0]
                }
                sig.recv = recv
+       }
+       params, variadic := check.collectParams(scope, ftyp.Params, true, scopePos)
+       results, _ := check.collectParams(scope, ftyp.Results, false, scopePos)
+
+       scope.squash(func(obj, alt Object) {
+               err := check.newError(DuplicateDecl)
+               err.addf(obj, "%s redeclared in this block", obj.Name())
+               err.addAltDecl(alt)
+               err.report()
+       })
 
+       if recv != nil {
                // Delay validation of receiver type as it may cause premature expansion
                // of types the receiver type is dependent on (see issues go.dev/issue/51232, go.dev/issue/51233).
                check.later(func() {