diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index e4ff21d4a1..10c82dbebd 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -435,6 +435,7 @@ type ( // A FuncType node represents a function type. FuncType struct { Func token.Pos // position of "func" keyword (token.NoPos if there is no "func") + TParams *FieldList // type parameters; or nil Params *FieldList // (incoming) parameters; non-nil Results *FieldList // (outgoing) results; or nil } @@ -994,12 +995,11 @@ type ( // A FuncDecl node represents a function declaration. FuncDecl struct { - Doc *CommentGroup // associated documentation; or nil - Recv *FieldList // receiver (methods); or nil (functions) - Name *Ident // function/method name - TParams *FieldList // type parameters; or nil - Type *FuncType // function signature: parameters, results, and position of "func" keyword - Body *BlockStmt // function body; or nil for external (non-Go) function + Doc *CommentGroup // associated documentation; or nil + Recv *FieldList // receiver (methods); or nil (functions) + Name *Ident // function/method name + Type *FuncType // function signature: type and value parameters, results, and position of "func" keyword + Body *BlockStmt // function body; or nil for external (non-Go) function } ) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index e6aa287edc..c94f80a149 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -1134,9 +1134,9 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { // method idents = []*ast.Ident{ident} scope := ast.NewScope(nil) // method scope - _, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method") + tparams, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method") results := p.parseResult(scope, true) - typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} + typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results} } else { // embedded interface typ = x @@ -1256,9 +1256,9 @@ func (p *parser) parseConstraint() *ast.Constraint { // method mname = ident scope := ast.NewScope(nil) // method scope - _, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method") + tparams, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method") results := p.parseResult(scope, true) - typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} + typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results} } mnames = append(mnames, mname) types = append(types, typ) @@ -2807,12 +2807,12 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { } decl := &ast.FuncDecl{ - Doc: doc, - Recv: recv, - Name: ident, - TParams: tparams, + Doc: doc, + Recv: recv, + Name: ident, Type: &ast.FuncType{ Func: pos, + TParams: tparams, Params: params, Results: results, }, diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index ed5c17f1b8..e903b9465d 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -384,22 +384,26 @@ func (p *printer) parameters(isTypeParam bool, fields *ast.FieldList) { p.print(fields.Closing, token.RPAREN) } -func (p *printer) signature(params, result *ast.FieldList) { - if params != nil { - p.parameters(false, params) +func (p *printer) signature(sig *ast.FuncType) { + if sig.TParams != nil { + p.parameters(true, sig.TParams) + } + if sig.Params != nil { + p.parameters(false, sig.Params) } else { p.print(token.LPAREN, token.RPAREN) } - n := result.NumFields() + res := sig.Results + n := res.NumFields() if n > 0 { - // result != nil + // res != nil p.print(blank) - if n == 1 && result.List[0].Names == nil { - // single anonymous result; no ()'s - p.expr(stripParensAlways(result.List[0].Type)) + if n == 1 && res.List[0].Names == nil { + // single anonymous res; no ()'s + p.expr(stripParensAlways(res.List[0].Type)) return } - p.parameters(false, result) + p.parameters(false, res) } } @@ -472,7 +476,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { // method p.expr(f.Names[0]) - p.signature(ftyp.Params, ftyp.Results) + p.signature(ftyp) } else { // embedded interface p.expr(f.Type) @@ -549,7 +553,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { // method p.expr(f.Names[0]) - p.signature(ftyp.Params, ftyp.Results) + p.signature(ftyp) } else { // embedded interface p.expr(f.Type) @@ -802,7 +806,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { p.print(x.Type.Pos(), token.FUNC) // See the comment in funcDecl about how the header size is computed. startCol := p.out.Column - len("func") - p.signature(x.Type.Params, x.Type.Results) + p.signature(x.Type) p.funcBody(p.distanceFrom(x.Type.Pos(), startCol), blank, x.Body) case *ast.ParenExpr: @@ -947,7 +951,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { case *ast.FuncType: p.print(token.FUNC) - p.signature(x.Params, x.Results) + p.signature(x) case *ast.InterfaceType: p.print(token.INTERFACE) @@ -1075,7 +1079,7 @@ func (p *printer) constraint(x *ast.Constraint) { for i, m := range x.MNames { p.print(m) t := x.Types[i].(*ast.FuncType) - p.signature(t.Params, t.Results) + p.signature(t) //p.print(token.COMMA) } } @@ -1821,10 +1825,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) { p.print(blank) } p.expr(d.Name) - if d.TParams != nil { - p.parameters(true, d.TParams) - } - p.signature(d.Type.Params, d.Type.Results) + p.signature(d.Type) p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body) } diff --git a/src/go/types/decl.go b/src/go/types/decl.go index a8d8bc0f0c..849560ffaa 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -770,7 +770,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) { saved := obj.color_ obj.color_ = black fdecl := decl.fdecl - check.funcType(sig, fdecl.Recv, fdecl.TParams, fdecl.Type) + check.funcType(sig, fdecl.Recv, fdecl.Type) obj.color_ = saved // function body must be type-checked after global declarations diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 9c74fbf70d..c20da1f66a 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -415,8 +415,8 @@ func (check *Checker) collectObjects() { // treat as function } if name == "init" { - if d.TParams != nil { - check.softErrorf(d.TParams.Pos(), "func init must have no type parameters") + if d.Type.TParams != nil { + check.softErrorf(d.Type.TParams.Pos(), "func init must have no type parameters") } if t := d.Type; t.Params.NumFields() != 0 || t.Results != nil { check.softErrorf(d.Pos(), "func init must have no arguments and no return values") @@ -435,8 +435,8 @@ func (check *Checker) collectObjects() { } else { // method // d.Recv != nil && len(d.Recv.List) > 0 - if !methodTypeParamsOk && d.TParams != nil { - check.invalidAST(d.TParams.Pos(), "method must have no type parameters") + if !methodTypeParamsOk && d.Type.TParams != nil { + check.invalidAST(d.Type.TParams.Pos(), "method must have no type parameters") } ptr, recv, _ := check.unpackRecv(d.Recv.List[0].Type, false) // (Methods with invalid receiver cannot be associated to a type, and diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index 71ec59b385..36a20173e7 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -4,4 +4,13 @@ package p -type S(type T) struct{}; func (S) _() +type I interface{ + m(type T)(T) +} + +type S struct{} + +func (S) m(type T)(T) + +// TODO(gri) this should work +var _ I = S /* ERROR wrong type for method m */ {} diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 58c69a50ba..84af3c039c 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -164,7 +164,7 @@ func (check *Checker) genericType(e ast.Expr, reportErr bool) Type { } // funcType type-checks a function or method type. -func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftparams *ast.FieldList, ftyp *ast.FuncType) { +func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { check.openScope(ftyp, "function") check.scope.isFunc = true check.recordScope(ftyp, check.scope) @@ -214,8 +214,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftparams } } - if ftparams != nil { - sig.tparams = check.collectTypeParams(ftparams) + if ftyp.TParams != nil { + sig.tparams = check.collectTypeParams(ftyp.TParams) } // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their @@ -391,7 +391,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) (T Type) { case *ast.FuncType: typ := new(Signature) def.setUnderlying(typ) - check.funcType(typ, nil, nil, e) + check.funcType(typ, nil, e) return typ case *ast.InterfaceType: