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 | 38 ++++++++++---------- src/go/types/signature.go | 31 ++++++++-------- 2 files changed, 36 insertions(+), 33 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,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() { 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() { -- 2.48.1