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 <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>
This commit is contained in:
Robert Griesemer 2024-06-18 10:34:11 -07:00 committed by Gopher Robot
parent 88bd985239
commit e0ca2e04b8
2 changed files with 38 additions and 35 deletions

View 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,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() {

View 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() {