diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 93e76e95c8..e6aa287edc 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -26,6 +26,8 @@ import ( "unicode" ) +const methodTypeParamsOk = typeParamsOk // set this to 0 to disallow type params in methods + // The parser structure holds the parser's internal state. type parser struct { file *token.File @@ -1132,7 +1134,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { // method idents = []*ast.Ident{ident} scope := ast.NewScope(nil) // method scope - _, params := p.parseParameters(scope, variadicOk, "method") + _, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method") results := p.parseResult(scope, true) typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} } else { @@ -1254,7 +1256,7 @@ func (p *parser) parseConstraint() *ast.Constraint { // method mname = ident scope := ast.NewScope(nil) // method scope - _, params := p.parseParameters(scope, variadicOk, "method") + _, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method") results := p.parseResult(scope, true) typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} } @@ -2785,7 +2787,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { ident := p.parseIdent() - tparams, params := p.parseParameters(scope, mode, "method") // context string only used in methods + tparams, params := p.parseParameters(scope, mode|methodTypeParamsOk, "method") // context string only used in methods results := p.parseResult(scope, true) var body *ast.BlockStmt diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 6cf09b2319..ade290d90c 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -49,10 +49,13 @@ var valids = []string{ `package p; type T = int`, `package p; type (T = p.T; _ = struct{}; x = *T)`, `package p; type T (*int)`, + + // type parameters `package p; type T(type P) struct { P }`, `package p; type T(type P comparable) struct { P }`, `package p; type T(type P comparable(P)) struct { P }`, `package p; type T(type P1, P2) struct { P1; f []P2 }`, + `package p; var _ = [](T(int)){}`, `package p; var _ = func()T(nil)`, `package p; func _(type)()`, @@ -63,9 +66,19 @@ var valids = []string{ `package p; func _(T [P]E)`, `package p; func _(x T(P1, P2, P3))`, `package p; func _((T(P1, P2, P3)))`, + + // method type parameters (if methodTypeParamsOk) `package p; func _(type A, B)(a A) B`, `package p; func _(type A, B C)(a A) B`, `package p; func _(type A, B C(A, B))(a A) B`, + `package p; func (T) _(type A, B)(a A) B`, + `package p; func (T) _(type A, B C)(a A) B`, + `package p; func (T) _(type A, B C(A, B))(a A) B`, + `package p; type _ interface { _(type A, B)(a A) B }`, + `package p; type _ interface { _(type A, B C)(a A) B }`, + `package p; type _ interface { _(type A, B C(A, B))(a A) B }`, + + // contracts `package p; contract C(){}`, `package p; contract C(T, S, R,){}`, `package p; contract C(T){ T (m(x, int)); }`, @@ -82,7 +95,7 @@ var valids = []string{ `package p; func _(type T1, T2 interface{})(x T1) T2`, `package p; func _(type T1 interface{ m() }, T2, T3 interface{})(x T1, y T3) T2`, - // interfaces as contracts (experimental) + // interfaces with (contract) type lists `package p; type _ interface{type int}`, `package p; type _ interface{type int, float32; type bool; m(); type string;}`, } @@ -146,6 +159,13 @@ var invalids = []string{ `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`, `package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`, //`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`, + + // type parameters + `package p; var _ func( /* ERROR "no type parameters" */ type T)(T)`, + `package p; func _() ( /* ERROR "no type parameters" */ type T)(T)`, + `package p; func ( /* ERROR "no type parameters" */ type T)(T) _()`, + + // contracts `package p; contract C(T, T /* ERROR "T redeclared" */ ) {}`, `package p; contract C(T) { imported /* ERROR "expected type parameter name" */ .T int }`,