From e0ca2e04b852e4c887be38f3ad7205a863b6c6a7 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 18 Jun 2024 10:34:11 -0700 Subject: [PATCH] go/types, types2: slightly reorganize method receiver checking - 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 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/signature.go | 42 ++++++++++---------- src/go/types/signature.go | 31 ++++++++------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index 7a5a2c155f..5050212e15 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -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,12 +176,29 @@ 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 + + // collect and typecheck receiver, incoming parameters, and results + var recv *Var if recvPar != nil { - recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, false, scopePos) // use rewritten receiver type, if any + // spec: "The receiver is specified via an extra parameter section preceding the + // method name. That parameter section must declare a single parameter, the receiver." + recvList, _ := check.collectParams(scope, []*syntax.Field{recvPar}, false, scopePos) // use rewritten receiver type, if any + switch len(recvList) { + case 0: + // error reported by parser + recv = NewParam(nopos, nil, "", Typ[Invalid]) // use invalid type so it's ignored by check.later code below + default: + // 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()) @@ -189,24 +206,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] err.report() }) - 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 - switch len(recvList) { - case 0: - // error reported by resolver - recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below - default: - // more than one receiver - check.error(recvList[len(recvList)-1].Pos(), InvalidRecv, "method must have exactly one receiver") - fallthrough // continue with first receiver - case 1: - recv = recvList[0] - } - sig.recv = recv - + 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() { diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 770edc2b21..9d83dd4fd5 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -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() {