From 8ce35843de20ec7db259ef7e21e8f5bcbd5cec57 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 7 Aug 2014 12:45:28 -0700 Subject: [PATCH] go.tools/go/types: handle all receiver errors in go/types Pending parser change in CL 123010044. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/125830043 --- go/types/testdata/decls2a.src | 20 ++++++++++++++++---- go/types/typexpr.go | 25 +++++++++++++++++-------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/go/types/testdata/decls2a.src b/go/types/testdata/decls2a.src index 6fe0f27d..bdbecd9d 100644 --- a/go/types/testdata/decls2a.src +++ b/go/types/testdata/decls2a.src @@ -80,12 +80,24 @@ type T5 interface { func (T5 /* ERROR "invalid receiver" */ ) m1() {} func (T5 /* ERROR "invalid receiver" */ ) m2() {} +// Methods associated with a named pointer type. +type ptr *int +func (ptr /* ERROR "invalid receiver" */ ) _() {} +func (* /* ERROR "invalid receiver" */ ptr) _() {} + +// Methods with zero or multiple receivers. +func ( /* ERROR "missing receiver" */ ) _() {} +func (T3, * /* ERROR "exactly one receiver" */ T3) _() {} +func (T3, T3, T3 /* ERROR "exactly one receiver" */ ) _() {} +func (a, b /* ERROR "exactly one receiver" */ T3) _() {} +func (a, b, c /* ERROR "exactly one receiver" */ T3) _() {} + // Methods associated with non-local or unnamed types. func (int /* ERROR "invalid receiver" */ ) m() {} -func ([ /* ERROR "identifier" */ ]int) m() {} -func (time /* ERROR "identifier" */ .Time) m() {} -func (*time /* ERROR "identifier" */ .Time) m() {} -func (x interface /* ERROR "identifier" */ {}) m() {} +func ([ /* ERROR "invalid receiver" */ ]int) m() {} +func (time /* ERROR "invalid receiver" */ .Time) m() {} +func (* /* ERROR "invalid receiver" */ time.Time) m() {} +func (x /* ERROR "invalid receiver" */ interface{}) m() {} // Unsafe.Pointer is treated like a pointer when used as receiver type. type UP unsafe.Pointer diff --git a/go/types/typexpr.go b/go/types/typexpr.go index fa239ac0..b939bd20 100644 --- a/go/types/typexpr.go +++ b/go/types/typexpr.go @@ -139,21 +139,30 @@ func (check *Checker) typ(e ast.Expr) Type { } // funcType type-checks a function or method type and returns its signature. -func (check *Checker) funcType(sig *Signature, recv *ast.FieldList, ftyp *ast.FuncType) *Signature { +func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) *Signature { scope := NewScope(check.scope, "function") check.recordScope(ftyp, scope) - recv_, _ := check.collectParams(scope, recv, false) + recvList, _ := check.collectParams(scope, recvPar, false) params, variadic := check.collectParams(scope, ftyp.Params, true) results, _ := check.collectParams(scope, ftyp.Results, false) - if len(recv_) > 0 { - // There must be exactly one receiver. - if len(recv_) > 1 { - check.invalidAST(recv_[1].Pos(), "method must have exactly one receiver") - // ok to continue + if recvPar != nil { + // recv parameter list present (may be empty) + // spec: "The receiver is specified via an extra parameter section preceeding the + // method name. That parameter section must declare a single parameter, the receiver." + var recv *Var + switch len(recvList) { + case 0: + check.error(recvPar.Pos(), "method is missing receiver") + recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below + default: + // more than one receiver + check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver") + fallthrough // continue with first receiver + case 1: + recv = recvList[0] } - recv := recv_[0] // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) if t, _ := deref(recv.typ); t != Typ[Invalid] {