diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index 16da0012f5..ef207f6cac 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -921,12 +921,16 @@ type ( type Constraint struct { // Invariant: Param == nil || len(MNames) == len(Types) // MNames entries will be nil if we have a list of types - Param *Ident // constrained type parameter; or nil (for embedded contracts) - MNames []*Ident // list of method names; or nil (for embedded contracts or type constraints) - Types []Expr // embedded contract (single *CallExpr), list of types, or list of method signatures (*FuncType) + Star token.Pos // position of "*"; or token.NoPos if not present + Param *Ident // constrained type parameter; or nil (for embedded contracts) + MNames []*Ident // list of method names; or nil (for embedded contracts or type constraints) + Types []Expr // embedded contract (single *CallExpr), list of types, or list of method signatures (*FuncType) } func (c *Constraint) Pos() token.Pos { + if c.Star.IsValid() { + return c.Star + } if c.Param != nil { return c.Param.Pos() } diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 7a8c67d08b..c94eb83b9c 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -2582,7 +2582,7 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token return spec } -// Constraint = TypeParam TypeOrMethod { "," TypeOrMethod } | ContractName "(" [ TypeList [ "," ] ] ")" . +// Constraint = [ "*" ] TypeParam TypeOrMethod { "," TypeOrMethod } | ContractName "(" [ TypeList [ "," ] ] ")" . // TypeParam = Ident . // TypeOrMethod = Type | MethodName Signature . // ContractName = TypeName. @@ -2598,9 +2598,18 @@ func (p *parser) parseConstraint() *ast.Constraint { return &ast.Constraint{Types: []ast.Expr{p.parseType(true)}} } + var star token.Pos + if p.tok == token.MUL { + star = p.pos + p.next() + } + tname := p.parseTypeName(nil) if p.tok == token.LPAREN { // ContractName "(" [ TypeList [ "," ] ] ")" + if star.IsValid() { + p.error(star, "pointer type requires a method") + } return &ast.Constraint{Types: []ast.Expr{p.parseTypeInstance(tname)}} } @@ -2627,6 +2636,10 @@ func (p *parser) parseConstraint() *ast.Constraint { tparams, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method") results := p.parseResult(scope, true) typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results} + } else if star.IsValid() { + // type with (invalid) starred type parameter + p.error(star, "pointer type requires a method") + star = token.NoPos // suppress further errors } mnames = append(mnames, mname) types = append(types, typ) @@ -2638,7 +2651,7 @@ func (p *parser) parseConstraint() *ast.Constraint { } // param != nil - return &ast.Constraint{Param: param, MNames: mnames, Types: types} + return &ast.Constraint{Star: star, Param: param, MNames: mnames, Types: types} } // ContractSpec = ident "(" [ IdentList [ "," ] ] ")" "{" { Constraint ";" } "}" . diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 8fa7d4a28a..25d061e0d3 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -98,6 +98,7 @@ var valids = []string{ `package p; contract C(T){ T int; T imported.T; T chan<-int; T m(x int) float64; C0(); imported.C1(int, T,) }`, `package p; contract C(T){ T int, imported.T, chan<-int; T m(x int) float64; C0(); imported.C1(int, T,) }`, `package p; contract C(T){ (C(T)); (((imported.T))) }`, + `package p; contract C(T){ *T m() }`, `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`, @@ -179,6 +180,8 @@ var invalids = []string{ // contracts `package p; contract C(T, T /* ERROR "T redeclared" */ ) {}`, `package p; contract C(T) { imported /* ERROR "expected type parameter name" */ .T int }`, + `package p; contract C(T) { * /* ERROR "requires a method" */ C(T) }`, + `package p; contract C(T) { * /* ERROR "requires a method" */ T int }`, `package p; func _() { contract /* ERROR "cannot be inside function" */ C(T) { T m(); type int, float32 } }`, // issue 8656