mirror of https://github.com/golang/go.git
cmd/compile/internal/syntax: accept Go2 syntax
Specifically, this change accepts now:
1) Type parameters in type and function declarations, such as:
type B(type T) interface {
m(T) T
}
func f(type T B) (list []T) T
2) Type instantiations:
type T B(int)
3) Embedded instantiated types, with necessary extra parentheses:
type T struct {
(B(int)) // ()'s to distinguish from field B of type (int)
}
type T interface {
(B(int)) // ()'s to distinguish from method B with int argument
}
The compiler simply ignores the new constructs.
Change-Id: Iecb8354d3846d7a5786cbe7d92870d8a2d578133
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go2-dev/+/736539
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
bc3ba78503
commit
70f1138c60
|
|
@ -74,11 +74,12 @@ type (
|
|||
|
||||
// Name Type
|
||||
TypeDecl struct {
|
||||
Group *Group // nil means not part of a group
|
||||
Pragma Pragma
|
||||
Name *Name
|
||||
Alias bool
|
||||
Type Expr
|
||||
Group *Group // nil means not part of a group
|
||||
Pragma Pragma
|
||||
Name *Name
|
||||
TParamList []*Field // nil means no type parameters
|
||||
Alias bool
|
||||
Type Expr
|
||||
decl
|
||||
}
|
||||
|
||||
|
|
@ -99,11 +100,12 @@ type (
|
|||
// func Receiver Name Type { Body }
|
||||
// func Receiver Name Type
|
||||
FuncDecl struct {
|
||||
Pragma Pragma
|
||||
Recv *Field // nil means regular function
|
||||
Name *Name
|
||||
Type *FuncType
|
||||
Body *BlockStmt // nil means no body (forward declaration)
|
||||
Pragma Pragma
|
||||
Recv *Field // nil means regular function
|
||||
Name *Name
|
||||
TParamList []*Field // nil means no type parameters
|
||||
Type *FuncType
|
||||
Body *BlockStmt // nil means no body (forward declaration)
|
||||
decl
|
||||
}
|
||||
)
|
||||
|
|
@ -273,6 +275,7 @@ type (
|
|||
// interface { MethodList[0]; MethodList[1]; ... }
|
||||
InterfaceType struct {
|
||||
MethodList []*Field
|
||||
TypeList []Expr
|
||||
expr
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -458,20 +458,21 @@ func isEmptyFuncDecl(dcl Decl) bool {
|
|||
// Declarations
|
||||
|
||||
// list parses a possibly empty, sep-separated list, optionally
|
||||
// followed by sep and enclosed by ( and ) or { and }. open is
|
||||
// one of _Lparen, or _Lbrace, sep is one of _Comma or _Semi,
|
||||
// and close is expected to be the (closing) opposite of open.
|
||||
// followed sep, and closed by close. sep must be one of _Comma
|
||||
// or _Semi, and close must be one of _Rparen or _Rbrace.
|
||||
// For each list element, f is called. After f returns true, no
|
||||
// more list elements are accepted. list returns the position
|
||||
// of the closing token.
|
||||
//
|
||||
// list = "(" { f sep } ")" |
|
||||
// "{" { f sep } "}" . // sep is optional before ")" or "}"
|
||||
// list = { f sep } ")" |
|
||||
// { f sep } "}" . // sep is optional before ")" or "}"
|
||||
//
|
||||
func (p *parser) list(open, sep, close token, f func() bool) Pos {
|
||||
p.want(open)
|
||||
func (p *parser) list(sep, close token, f func() bool) Pos {
|
||||
if debug && (sep != _Comma && sep != _Semi || close != _Rparen && close != _Rbrace) {
|
||||
panic("invalid sep or close argument for list")
|
||||
}
|
||||
|
||||
var done bool
|
||||
done := false
|
||||
for p.tok != _EOF && p.tok != close && !done {
|
||||
done = f()
|
||||
// sep is optional before close
|
||||
|
|
@ -492,10 +493,10 @@ func (p *parser) list(open, sep, close token, f func() bool) Pos {
|
|||
|
||||
// appendGroup(f) = f | "(" { f ";" } ")" . // ";" is optional before ")"
|
||||
func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
|
||||
if p.tok == _Lparen {
|
||||
if p.got(_Lparen) {
|
||||
g := new(Group)
|
||||
p.clearPragma()
|
||||
p.list(_Lparen, _Semi, _Rparen, func() bool {
|
||||
p.list(_Semi, _Rparen, func() bool {
|
||||
list = append(list, f(g))
|
||||
return false
|
||||
})
|
||||
|
|
@ -556,7 +557,7 @@ func (p *parser) constDecl(group *Group) Decl {
|
|||
|
||||
d.NameList = p.nameList(p.name())
|
||||
if p.tok != _EOF && p.tok != _Semi && p.tok != _Rparen {
|
||||
d.Type = p.typeOrNil()
|
||||
d.Type = p.typeOrNil(true)
|
||||
if p.gotAssign() {
|
||||
d.Values = p.exprList()
|
||||
}
|
||||
|
|
@ -565,7 +566,7 @@ func (p *parser) constDecl(group *Group) Decl {
|
|||
return d
|
||||
}
|
||||
|
||||
// TypeSpec = identifier [ "=" ] Type .
|
||||
// TypeSpec = identifier [ TypeParams ] [ "=" ] Type .
|
||||
func (p *parser) typeDecl(group *Group) Decl {
|
||||
if trace {
|
||||
defer p.trace("typeDecl")()
|
||||
|
|
@ -577,8 +578,23 @@ func (p *parser) typeDecl(group *Group) Decl {
|
|||
d.Pragma = p.takePragma()
|
||||
|
||||
d.Name = p.name()
|
||||
d.Alias = p.gotAssign()
|
||||
d.Type = p.typeOrNil()
|
||||
if p.got(_Lparen) {
|
||||
if p.got(_Type) {
|
||||
// parameterized type
|
||||
d.TParamList = p.paramList(true)
|
||||
d.Alias = p.gotAssign()
|
||||
d.Type = p.typeOrNil(true)
|
||||
} else {
|
||||
// parenthesized type
|
||||
d.Type = p.typeOrNil(true)
|
||||
p.want(_Rparen)
|
||||
}
|
||||
} else {
|
||||
// no type parameters
|
||||
d.Alias = p.gotAssign()
|
||||
d.Type = p.typeOrNil(true)
|
||||
}
|
||||
|
||||
if d.Type == nil {
|
||||
d.Type = p.badExpr()
|
||||
p.syntaxError("in type declaration")
|
||||
|
|
@ -603,7 +619,7 @@ func (p *parser) varDecl(group *Group) Decl {
|
|||
if p.gotAssign() {
|
||||
d.Values = p.exprList()
|
||||
} else {
|
||||
d.Type = p.type_()
|
||||
d.Type = p.type_(true)
|
||||
if p.gotAssign() {
|
||||
d.Values = p.exprList()
|
||||
}
|
||||
|
|
@ -612,7 +628,7 @@ func (p *parser) varDecl(group *Group) Decl {
|
|||
return d
|
||||
}
|
||||
|
||||
// FunctionDecl = "func" FunctionName ( Function | Signature ) .
|
||||
// FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) .
|
||||
// FunctionName = identifier .
|
||||
// Function = Signature FunctionBody .
|
||||
// MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
|
||||
|
|
@ -626,8 +642,8 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
|
|||
f.pos = p.pos()
|
||||
f.Pragma = p.takePragma()
|
||||
|
||||
if p.tok == _Lparen {
|
||||
rcvr := p.paramList()
|
||||
if p.got(_Lparen) {
|
||||
rcvr := p.paramList(false)
|
||||
switch len(rcvr) {
|
||||
case 0:
|
||||
p.error("method has no receiver")
|
||||
|
|
@ -646,7 +662,13 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
|
|||
}
|
||||
|
||||
f.Name = p.name()
|
||||
f.Type = p.funcType()
|
||||
tpos := p.pos()
|
||||
p.want(_Lparen)
|
||||
if p.got(_Type) {
|
||||
p.paramList(true)
|
||||
p.want(_Lparen)
|
||||
}
|
||||
f.Type = p.funcType(tpos, true)
|
||||
if p.tok == _Lbrace {
|
||||
f.Body = p.funcBody()
|
||||
}
|
||||
|
|
@ -849,13 +871,7 @@ func (p *parser) operand(keep_parens bool) Expr {
|
|||
// Optimization: Record presence of ()'s only where needed
|
||||
// for error reporting. Don't bother in other cases; it is
|
||||
// just a waste of memory and time.
|
||||
|
||||
// Parentheses are not permitted on lhs of := .
|
||||
// switch x.Op {
|
||||
// case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
|
||||
// keep_parens = true
|
||||
// }
|
||||
|
||||
//
|
||||
// Parentheses are not permitted around T in a composite
|
||||
// literal T{}. If the next token is a {, assume x is a
|
||||
// composite literal type T (it may not be, { could be
|
||||
|
|
@ -876,24 +892,26 @@ func (p *parser) operand(keep_parens bool) Expr {
|
|||
return x
|
||||
|
||||
case _Func:
|
||||
pos := p.pos()
|
||||
fpos := p.pos()
|
||||
p.next()
|
||||
t := p.funcType()
|
||||
tpos := p.pos()
|
||||
p.want(_Lparen)
|
||||
ftyp := p.funcType(tpos, false)
|
||||
if p.tok == _Lbrace {
|
||||
p.xnest++
|
||||
|
||||
f := new(FuncLit)
|
||||
f.pos = pos
|
||||
f.Type = t
|
||||
f.pos = fpos
|
||||
f.Type = ftyp
|
||||
f.Body = p.funcBody()
|
||||
|
||||
p.xnest--
|
||||
return f
|
||||
}
|
||||
return t
|
||||
return ftyp
|
||||
|
||||
case _Lbrack, _Chan, _Map, _Struct, _Interface:
|
||||
return p.type_() // othertype
|
||||
return p.type_(false) // othertype
|
||||
|
||||
default:
|
||||
x := p.badExpr()
|
||||
|
|
@ -958,7 +976,7 @@ loop:
|
|||
t := new(AssertExpr)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Type = p.type_()
|
||||
t.Type = p.type_(true)
|
||||
x = t
|
||||
}
|
||||
p.want(_Rparen)
|
||||
|
|
@ -1029,7 +1047,7 @@ loop:
|
|||
// determine if '{' belongs to a composite literal or a block statement
|
||||
complit_ok := false
|
||||
switch t.(type) {
|
||||
case *Name, *SelectorExpr:
|
||||
case *Name, *SelectorExpr, *CallExpr: // *CallExpr for instantiated types
|
||||
if p.xnest >= 0 {
|
||||
// x is considered a composite literal type
|
||||
complit_ok = true
|
||||
|
|
@ -1045,7 +1063,9 @@ loop:
|
|||
p.syntaxError("cannot parenthesize type in composite literal")
|
||||
// already progressed, no need to advance
|
||||
}
|
||||
n := p.complitexpr()
|
||||
pos := p.pos()
|
||||
p.next() // consume _Lbrace
|
||||
n := p.complitexpr(pos)
|
||||
n.Type = x
|
||||
x = n
|
||||
|
||||
|
|
@ -1063,25 +1083,27 @@ func (p *parser) bare_complitexpr() Expr {
|
|||
defer p.trace("bare_complitexpr")()
|
||||
}
|
||||
|
||||
if p.tok == _Lbrace {
|
||||
pos := p.pos()
|
||||
if p.got(_Lbrace) {
|
||||
// '{' start_complit braced_keyval_list '}'
|
||||
return p.complitexpr()
|
||||
return p.complitexpr(pos)
|
||||
}
|
||||
|
||||
return p.expr()
|
||||
}
|
||||
|
||||
// LiteralValue = "{" [ ElementList [ "," ] ] "}" .
|
||||
func (p *parser) complitexpr() *CompositeLit {
|
||||
// "{" has already been consumed, and pos is its position.
|
||||
func (p *parser) complitexpr(pos Pos) *CompositeLit {
|
||||
if trace {
|
||||
defer p.trace("complitexpr")()
|
||||
}
|
||||
|
||||
x := new(CompositeLit)
|
||||
x.pos = p.pos()
|
||||
x.pos = pos
|
||||
|
||||
p.xnest++
|
||||
x.Rbrace = p.list(_Lbrace, _Comma, _Rbrace, func() bool {
|
||||
x.Rbrace = p.list(_Comma, _Rbrace, func() bool {
|
||||
// value
|
||||
e := p.bare_complitexpr()
|
||||
if p.tok == _Colon {
|
||||
|
|
@ -1105,12 +1127,12 @@ func (p *parser) complitexpr() *CompositeLit {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Types
|
||||
|
||||
func (p *parser) type_() Expr {
|
||||
func (p *parser) type_(inType bool) Expr {
|
||||
if trace {
|
||||
defer p.trace("type_")()
|
||||
}
|
||||
|
||||
typ := p.typeOrNil()
|
||||
typ := p.typeOrNil(inType)
|
||||
if typ == nil {
|
||||
typ = p.badExpr()
|
||||
p.syntaxError("expecting type")
|
||||
|
|
@ -1135,7 +1157,7 @@ func newIndirect(pos Pos, typ Expr) Expr {
|
|||
// TypeName = identifier | QualifiedIdent .
|
||||
// TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
||||
// SliceType | MapType | Channel_Type .
|
||||
func (p *parser) typeOrNil() Expr {
|
||||
func (p *parser) typeOrNil(inType bool) Expr {
|
||||
if trace {
|
||||
defer p.trace("typeOrNil")()
|
||||
}
|
||||
|
|
@ -1145,7 +1167,7 @@ func (p *parser) typeOrNil() Expr {
|
|||
case _Star:
|
||||
// ptrtype
|
||||
p.next()
|
||||
return newIndirect(pos, p.type_())
|
||||
return newIndirect(pos, p.type_(inType))
|
||||
|
||||
case _Arrow:
|
||||
// recvchantype
|
||||
|
|
@ -1154,13 +1176,15 @@ func (p *parser) typeOrNil() Expr {
|
|||
t := new(ChanType)
|
||||
t.pos = pos
|
||||
t.Dir = RecvOnly
|
||||
t.Elem = p.chanElem()
|
||||
t.Elem = p.chanElem(inType)
|
||||
return t
|
||||
|
||||
case _Func:
|
||||
// fntype
|
||||
p.next()
|
||||
return p.funcType()
|
||||
tpos := p.pos()
|
||||
p.want(_Lparen)
|
||||
return p.funcType(tpos, inType)
|
||||
|
||||
case _Lbrack:
|
||||
// '[' oexpr ']' ntype
|
||||
|
|
@ -1172,7 +1196,7 @@ func (p *parser) typeOrNil() Expr {
|
|||
p.xnest--
|
||||
t := new(SliceType)
|
||||
t.pos = pos
|
||||
t.Elem = p.type_()
|
||||
t.Elem = p.type_(inType)
|
||||
return t
|
||||
}
|
||||
|
||||
|
|
@ -1184,7 +1208,7 @@ func (p *parser) typeOrNil() Expr {
|
|||
}
|
||||
p.want(_Rbrack)
|
||||
p.xnest--
|
||||
t.Elem = p.type_()
|
||||
t.Elem = p.type_(inType)
|
||||
return t
|
||||
|
||||
case _Chan:
|
||||
|
|
@ -1196,7 +1220,7 @@ func (p *parser) typeOrNil() Expr {
|
|||
if p.got(_Arrow) {
|
||||
t.Dir = SendOnly
|
||||
}
|
||||
t.Elem = p.chanElem()
|
||||
t.Elem = p.chanElem(inType)
|
||||
return t
|
||||
|
||||
case _Map:
|
||||
|
|
@ -1205,9 +1229,9 @@ func (p *parser) typeOrNil() Expr {
|
|||
p.want(_Lbrack)
|
||||
t := new(MapType)
|
||||
t.pos = pos
|
||||
t.Key = p.type_()
|
||||
t.Key = p.type_(true)
|
||||
p.want(_Rbrack)
|
||||
t.Value = p.type_()
|
||||
t.Value = p.type_(inType)
|
||||
return t
|
||||
|
||||
case _Struct:
|
||||
|
|
@ -1217,11 +1241,15 @@ func (p *parser) typeOrNil() Expr {
|
|||
return p.interfaceType()
|
||||
|
||||
case _Name:
|
||||
return p.dotname(p.name())
|
||||
t := p.dotname(p.name())
|
||||
if inType && p.tok == _Lparen {
|
||||
t = p.typeInstance(t)
|
||||
}
|
||||
return t
|
||||
|
||||
case _Lparen:
|
||||
p.next()
|
||||
t := p.type_()
|
||||
t := p.type_(true)
|
||||
p.want(_Rparen)
|
||||
return t
|
||||
}
|
||||
|
|
@ -1229,25 +1257,46 @@ func (p *parser) typeOrNil() Expr {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) funcType() *FuncType {
|
||||
func (p *parser) typeInstance(typ Expr) *CallExpr {
|
||||
if trace {
|
||||
defer p.trace("typeInstance")()
|
||||
}
|
||||
|
||||
x := new(CallExpr)
|
||||
x.pos = p.pos()
|
||||
x.Fun = typ
|
||||
|
||||
p.xnest++
|
||||
p.want(_Lparen)
|
||||
p.list(_Comma, _Rparen, func() bool {
|
||||
x.ArgList = append(x.ArgList, p.expr())
|
||||
return false
|
||||
})
|
||||
p.xnest--
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
// "(" has already been consumed, and pos is its position.
|
||||
func (p *parser) funcType(pos Pos, inType bool) *FuncType {
|
||||
if trace {
|
||||
defer p.trace("funcType")()
|
||||
}
|
||||
|
||||
typ := new(FuncType)
|
||||
typ.pos = p.pos()
|
||||
typ.ParamList = p.paramList()
|
||||
typ.ResultList = p.funcResult()
|
||||
typ.pos = pos
|
||||
typ.ParamList = p.paramList(false)
|
||||
typ.ResultList = p.funcResult(inType)
|
||||
|
||||
return typ
|
||||
}
|
||||
|
||||
func (p *parser) chanElem() Expr {
|
||||
func (p *parser) chanElem(inType bool) Expr {
|
||||
if trace {
|
||||
defer p.trace("chanElem")()
|
||||
}
|
||||
|
||||
typ := p.typeOrNil()
|
||||
typ := p.typeOrNil(inType)
|
||||
if typ == nil {
|
||||
typ = p.badExpr()
|
||||
p.syntaxError("missing channel element type")
|
||||
|
|
@ -1283,7 +1332,8 @@ func (p *parser) structType() *StructType {
|
|||
typ.pos = p.pos()
|
||||
|
||||
p.want(_Struct)
|
||||
p.list(_Lbrace, _Semi, _Rbrace, func() bool {
|
||||
p.want(_Lbrace)
|
||||
p.list(_Semi, _Rbrace, func() bool {
|
||||
p.fieldDecl(typ)
|
||||
return false
|
||||
})
|
||||
|
|
@ -1301,9 +1351,27 @@ func (p *parser) interfaceType() *InterfaceType {
|
|||
typ.pos = p.pos()
|
||||
|
||||
p.want(_Interface)
|
||||
p.list(_Lbrace, _Semi, _Rbrace, func() bool {
|
||||
if m := p.methodDecl(); m != nil {
|
||||
typ.MethodList = append(typ.MethodList, m)
|
||||
p.want(_Lbrace)
|
||||
p.list(_Semi, _Rbrace, func() bool {
|
||||
switch p.tok {
|
||||
case _Name, _Lparen:
|
||||
if m := p.methodDecl(); m != nil {
|
||||
typ.MethodList = append(typ.MethodList, m)
|
||||
}
|
||||
case _Type:
|
||||
p.next()
|
||||
var list []Expr
|
||||
if p.tok != _Semi && p.tok != _Rbrace {
|
||||
list = append(list, p.type_(true))
|
||||
for p.got(_Comma) {
|
||||
list = append(list, p.type_(true))
|
||||
}
|
||||
}
|
||||
typ.TypeList = list
|
||||
|
||||
default:
|
||||
p.syntaxError("expecting method or interface name")
|
||||
p.advance(_Semi, _Rbrace)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
|
@ -1312,17 +1380,17 @@ func (p *parser) interfaceType() *InterfaceType {
|
|||
}
|
||||
|
||||
// Result = Parameters | Type .
|
||||
func (p *parser) funcResult() []*Field {
|
||||
func (p *parser) funcResult(inType bool) []*Field {
|
||||
if trace {
|
||||
defer p.trace("funcResult")()
|
||||
}
|
||||
|
||||
if p.tok == _Lparen {
|
||||
return p.paramList()
|
||||
if p.got(_Lparen) {
|
||||
return p.paramList(false)
|
||||
}
|
||||
|
||||
pos := p.pos()
|
||||
if typ := p.typeOrNil(); typ != nil {
|
||||
if typ := p.typeOrNil(inType); typ != nil {
|
||||
f := new(Field)
|
||||
f.pos = pos
|
||||
f.Type = typ
|
||||
|
|
@ -1364,59 +1432,33 @@ func (p *parser) fieldDecl(styp *StructType) {
|
|||
case _Name:
|
||||
name := p.name()
|
||||
if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
|
||||
// embed oliteral
|
||||
// embedded type
|
||||
typ := p.qualifiedName(name)
|
||||
if p.tok == _Lparen {
|
||||
typ = p.typeInstance(typ)
|
||||
}
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
return
|
||||
}
|
||||
|
||||
// new_name_list ntype oliteral
|
||||
// name1, name2, ... Type [ tag ]
|
||||
names := p.nameList(name)
|
||||
typ := p.type_()
|
||||
typ := p.type_(true)
|
||||
tag := p.oliteral()
|
||||
|
||||
for _, name := range names {
|
||||
p.addField(styp, name.Pos(), name, typ, tag)
|
||||
}
|
||||
|
||||
case _Lparen:
|
||||
p.next()
|
||||
if p.tok == _Star {
|
||||
// '(' '*' embed ')' oliteral
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
typ := newIndirect(pos, p.qualifiedName(nil))
|
||||
p.want(_Rparen)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
p.syntaxError("cannot parenthesize embedded type")
|
||||
|
||||
} else {
|
||||
// '(' embed ')' oliteral
|
||||
typ := p.qualifiedName(nil)
|
||||
p.want(_Rparen)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
p.syntaxError("cannot parenthesize embedded type")
|
||||
}
|
||||
|
||||
case _Star:
|
||||
p.next()
|
||||
if p.got(_Lparen) {
|
||||
// '*' '(' embed ')' oliteral
|
||||
typ := newIndirect(pos, p.qualifiedName(nil))
|
||||
p.want(_Rparen)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
p.syntaxError("cannot parenthesize embedded type")
|
||||
|
||||
} else {
|
||||
// '*' embed oliteral
|
||||
typ := newIndirect(pos, p.qualifiedName(nil))
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
}
|
||||
case _Lparen, _Star:
|
||||
// embedded, possibly parameterized type
|
||||
// (using the enclosing parentheses to distinguish it from a named field declaration)
|
||||
// TODO(gri) This may be too liberal. Maybe only permit ()'s if necessary.
|
||||
// See also fixedbugs/bug299.go.
|
||||
typ := p.type_(true)
|
||||
tag := p.oliteral()
|
||||
p.addField(styp, pos, nil, typ, tag)
|
||||
|
||||
default:
|
||||
p.syntaxError("expecting field name or embedded type")
|
||||
|
|
@ -1462,18 +1504,18 @@ func (p *parser) methodDecl() *Field {
|
|||
|
||||
f := new(Field)
|
||||
f.pos = name.Pos()
|
||||
if p.tok != _Lparen {
|
||||
// packname
|
||||
tpos := p.pos()
|
||||
if p.got(_Lparen) {
|
||||
// method
|
||||
f.Name = name
|
||||
f.Type = p.funcType(tpos, true)
|
||||
} else {
|
||||
// embedded interface
|
||||
f.Type = p.qualifiedName(name)
|
||||
return f
|
||||
}
|
||||
|
||||
f.Name = name
|
||||
f.Type = p.funcType()
|
||||
return f
|
||||
|
||||
case _Lparen:
|
||||
p.syntaxError("cannot parenthesize embedded type")
|
||||
f := new(Field)
|
||||
f.pos = p.pos()
|
||||
p.next()
|
||||
|
|
@ -1482,9 +1524,7 @@ func (p *parser) methodDecl() *Field {
|
|||
return f
|
||||
|
||||
default:
|
||||
p.syntaxError("expecting method or interface name")
|
||||
p.advance(_Semi, _Rbrace)
|
||||
return nil
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1503,7 +1543,7 @@ func (p *parser) paramDeclOrNil() *Field {
|
|||
switch p.tok {
|
||||
case _Name, _Star, _Arrow, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
|
||||
// sym name_or_type
|
||||
f.Type = p.type_()
|
||||
f.Type = p.type_(true)
|
||||
|
||||
case _DotDotDot:
|
||||
// sym dotdotdot
|
||||
|
|
@ -1518,7 +1558,7 @@ func (p *parser) paramDeclOrNil() *Field {
|
|||
|
||||
case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
|
||||
// name_or_type
|
||||
f.Type = p.type_()
|
||||
f.Type = p.type_(true)
|
||||
|
||||
case _DotDotDot:
|
||||
// dotdotdot
|
||||
|
|
@ -1543,7 +1583,7 @@ func (p *parser) dotsType() *DotsType {
|
|||
t.pos = p.pos()
|
||||
|
||||
p.want(_DotDotDot)
|
||||
t.Elem = p.typeOrNil()
|
||||
t.Elem = p.typeOrNil(true)
|
||||
if t.Elem == nil {
|
||||
t.Elem = p.badExpr()
|
||||
p.syntaxError("final argument in variadic function missing type")
|
||||
|
|
@ -1554,15 +1594,17 @@ func (p *parser) dotsType() *DotsType {
|
|||
|
||||
// Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
||||
// ParameterList = ParameterDecl { "," ParameterDecl } .
|
||||
func (p *parser) paramList() (list []*Field) {
|
||||
// "(" has already been consumed.
|
||||
func (p *parser) paramList(tparams bool) (list []*Field) {
|
||||
if trace {
|
||||
defer p.trace("paramList")()
|
||||
}
|
||||
|
||||
// TODO(gri) use the actual position where the error happens
|
||||
pos := p.pos()
|
||||
|
||||
var named int // number of parameters that have an explicit name and type
|
||||
p.list(_Lparen, _Comma, _Rparen, func() bool {
|
||||
var named int // number of parameters that have an explicit name and type/bound
|
||||
p.list(_Comma, _Rparen, func() bool {
|
||||
if par := p.paramDeclOrNil(); par != nil {
|
||||
if debug && par.Name == nil && par.Type == nil {
|
||||
panic("parameter without name or type")
|
||||
|
|
@ -1577,7 +1619,7 @@ func (p *parser) paramList() (list []*Field) {
|
|||
|
||||
// distribute parameter types
|
||||
if named == 0 {
|
||||
// all unnamed => found names are named types
|
||||
// all unnamed => found names are named types or unbounded type parameters
|
||||
for _, par := range list {
|
||||
if typ := par.Name; typ != nil {
|
||||
par.Type = typ
|
||||
|
|
@ -1585,7 +1627,7 @@ func (p *parser) paramList() (list []*Field) {
|
|||
}
|
||||
}
|
||||
} else if named != len(list) {
|
||||
// some named => all must be named
|
||||
// some named => all must be named or bounded
|
||||
ok := true
|
||||
var typ Expr
|
||||
for i := len(list) - 1; i >= 0; i-- {
|
||||
|
|
@ -1608,7 +1650,11 @@ func (p *parser) paramList() (list []*Field) {
|
|||
}
|
||||
}
|
||||
if !ok {
|
||||
p.syntaxErrorAt(pos, "mixed named and unnamed function parameters")
|
||||
if tparams {
|
||||
p.syntaxErrorAt(pos, "mixed bounded and unbounded type parameters")
|
||||
} else {
|
||||
p.syntaxErrorAt(pos, "mixed named and unnamed function parameters")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2207,7 +2253,8 @@ func (p *parser) argList() (list []Expr, hasDots bool) {
|
|||
}
|
||||
|
||||
p.xnest++
|
||||
p.list(_Lparen, _Comma, _Rparen, func() bool {
|
||||
p.want(_Lparen)
|
||||
p.list(_Comma, _Rparen, func() bool {
|
||||
list = append(list, p.expr())
|
||||
hasDots = p.got(_DotDotDot)
|
||||
return hasDots
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
|
@ -29,6 +30,22 @@ func TestParse(t *testing.T) {
|
|||
ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
|
||||
}
|
||||
|
||||
func TestParseGo2(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t) // we need access to source (testdata)
|
||||
|
||||
dir := filepath.Join(testdata, "go2")
|
||||
list, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, fi := range list {
|
||||
name := fi.Name()
|
||||
if !fi.IsDir() && !strings.HasPrefix(name, ".") {
|
||||
ParseFile(filepath.Join(dir, name), func(err error) { t.Error(err) }, nil, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdLib(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package chans
|
||||
|
||||
import "runtime"
|
||||
|
||||
// Ranger returns a Sender and a Receiver. The Receiver provides a
|
||||
// Next method to retrieve values. The Sender provides a Send method
|
||||
// to send values and a Close method to stop sending values. The Next
|
||||
// method indicates when the Sender has been closed, and the Send
|
||||
// method indicates when the Receiver has been freed.
|
||||
//
|
||||
// This is a convenient way to exit a goroutine sending values when
|
||||
// the receiver stops reading them.
|
||||
func Ranger(type T)() (*Sender(T), *Receiver(T)) {
|
||||
c := make(chan T)
|
||||
d := make(chan bool)
|
||||
s := &Sender(T){values: c, done: d}
|
||||
r := &Receiver(T){values: c, done: d}
|
||||
runtime.SetFinalizer(r, r.finalize)
|
||||
return s, r
|
||||
}
|
||||
|
||||
// A sender is used to send values to a Receiver.
|
||||
type Sender(type T) struct {
|
||||
values chan<- T
|
||||
done <-chan bool
|
||||
}
|
||||
|
||||
// Send sends a value to the receiver. It returns whether any more
|
||||
// values may be sent; if it returns false the value was not sent.
|
||||
func (s *Sender(T)) Send(v T) bool {
|
||||
select {
|
||||
case s.values <- v:
|
||||
return true
|
||||
case <-s.done:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Close tells the receiver that no more values will arrive.
|
||||
// After Close is called, the Sender may no longer be used.
|
||||
func (s *Sender(T)) Close() {
|
||||
close(s.values)
|
||||
}
|
||||
|
||||
// A Receiver receives values from a Sender.
|
||||
type Receiver(type T) struct {
|
||||
values <-chan T
|
||||
done chan<- bool
|
||||
}
|
||||
|
||||
// Next returns the next value from the channel. The bool result
|
||||
// indicates whether the value is valid, or whether the Sender has
|
||||
// been closed and no more values will be received.
|
||||
func (r *Receiver(T)) Next() (T, bool) {
|
||||
v, ok := <-r.values
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// finalize is a finalizer for the receiver.
|
||||
func (r *Receiver(T)) finalize() {
|
||||
close(r.done)
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package linalg
|
||||
|
||||
import "math"
|
||||
|
||||
// Numeric is type bound that matches any numeric type.
|
||||
// It would likely be in a contracts package in the standard library.
|
||||
type Numeric interface {
|
||||
type int, int8, int16, int32, int64
|
||||
type uint, uint8, uint16, uint32, uint64, uintptr
|
||||
type float32, float64
|
||||
type complex64, complex128
|
||||
}
|
||||
|
||||
func DotProduct(type T Numeric)(s1, s2 []T) T {
|
||||
if len(s1) != len(s2) {
|
||||
panic("DotProduct: slices of unequal length")
|
||||
}
|
||||
var r T
|
||||
for i := range s1 {
|
||||
r += s1[i] * s2[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// NumericAbs matches numeric types with an Abs method.
|
||||
type NumericAbs(type T) interface {
|
||||
Numeric
|
||||
|
||||
Abs() T
|
||||
}
|
||||
|
||||
// AbsDifference computes the absolute value of the difference of
|
||||
// a and b, where the absolute value is determined by the Abs method.
|
||||
func AbsDifference(type T NumericAbs)(a, b T) T {
|
||||
d := a - b
|
||||
return d.Abs()
|
||||
}
|
||||
|
||||
// OrderedNumeric is a type bound that matches numeric types that support the < operator.
|
||||
type OrderedNumeric interface {
|
||||
type int, int8, int16, int32, int64
|
||||
type uint, uint8, uint16, uint32, uint64, uintptr
|
||||
type float32, float64
|
||||
}
|
||||
|
||||
// Complex is a type bound that matches the two complex types, which do not have a < operator.
|
||||
type Complex interface {
|
||||
type complex64, complex128
|
||||
}
|
||||
|
||||
// OrderedAbs is a helper type that defines an Abs method for
|
||||
// ordered numeric types.
|
||||
type OrderedAbs(type T OrderedNumeric) T
|
||||
|
||||
func (a OrderedAbs(T)) Abs() OrderedAbs(T) {
|
||||
if a < 0 {
|
||||
return -a
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ComplexAbs is a helper type that defines an Abs method for
|
||||
// complex types.
|
||||
type ComplexAbs(type T Complex) T
|
||||
|
||||
func (a ComplexAbs(T)) Abs() ComplexAbs(T) {
|
||||
r := float64(real(a))
|
||||
i := float64(imag(a))
|
||||
d := math.Sqrt(r * r + i * i)
|
||||
return T(complex(d, 0))
|
||||
}
|
||||
|
||||
func OrderedAbsDifference(type T OrderedNumeric)(a, b T) T {
|
||||
return T(AbsDifference(OrderedAbs(T)(a), OrderedAbs(T)(b)))
|
||||
}
|
||||
|
||||
func ComplexAbsDifference(type T Complex)(a, b T) T {
|
||||
return T(AbsDifference(ComplexAbs(T)(a), ComplexAbs(T)(b)))
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package orderedmap provides an ordered map, implemented as a binary tree.
|
||||
package orderedmap
|
||||
|
||||
// TODO(gri) fix imports for tests
|
||||
import "chans" // ERROR could not import
|
||||
|
||||
// Map is an ordered map.
|
||||
type Map(type K, V) struct {
|
||||
root *node(K, V)
|
||||
compare func(K, K) int
|
||||
}
|
||||
|
||||
// node is the type of a node in the binary tree.
|
||||
type node(type K, V) struct {
|
||||
key K
|
||||
val V
|
||||
left, right *node(K, V)
|
||||
}
|
||||
|
||||
// New returns a new map.
|
||||
func New(type K, V)(compare func(K, K) int) *Map(K, V) {
|
||||
return &Map(K, V){compare: compare}
|
||||
}
|
||||
|
||||
// find looks up key in the map, and returns either a pointer
|
||||
// to the node holding key, or a pointer to the location where
|
||||
// such a node would go.
|
||||
func (m *Map(K, V)) find(key K) **node(K, V) {
|
||||
pn := &m.root
|
||||
for *pn != nil {
|
||||
switch cmp := m.compare(key, (*pn).key); {
|
||||
case cmp < 0:
|
||||
pn = &(*pn).left
|
||||
case cmp > 0:
|
||||
pn = &(*pn).right
|
||||
default:
|
||||
return pn
|
||||
}
|
||||
}
|
||||
return pn
|
||||
}
|
||||
|
||||
// Insert inserts a new key/value into the map.
|
||||
// If the key is already present, the value is replaced.
|
||||
// Returns true if this is a new key, false if already present.
|
||||
func (m *Map(K, V)) Insert(key K, val V) bool {
|
||||
pn := m.find(key)
|
||||
if *pn != nil {
|
||||
(*pn).val = val
|
||||
return false
|
||||
}
|
||||
*pn = &node(K, V){key: key, val: val}
|
||||
return true
|
||||
}
|
||||
|
||||
// Find returns the value associated with a key, or zero if not present.
|
||||
// The found result reports whether the key was found.
|
||||
func (m *Map(K, V)) Find(key K) (V, bool) {
|
||||
pn := m.find(key)
|
||||
if *pn == nil {
|
||||
var zero V // see the discussion of zero values, above
|
||||
return zero, false
|
||||
}
|
||||
return (*pn).val, true
|
||||
}
|
||||
|
||||
// keyValue is a pair of key and value used when iterating.
|
||||
type keyValue(type K, V) struct {
|
||||
key K
|
||||
val V
|
||||
}
|
||||
|
||||
// InOrder returns an iterator that does an in-order traversal of the map.
|
||||
func (m *Map(K, V)) InOrder() *Iterator(K, V) {
|
||||
sender, receiver := chans.Ranger(keyValue(K, V))()
|
||||
var f func(*node(K, V)) bool
|
||||
f = func(n *node(K, V)) bool {
|
||||
if n == nil {
|
||||
return true
|
||||
}
|
||||
// Stop sending values if sender.Send returns false,
|
||||
// meaning that nothing is listening at the receiver end.
|
||||
return f(n.left) &&
|
||||
sender.Send(keyValue(K, V){n.key, n.val}) &&
|
||||
f(n.right)
|
||||
}
|
||||
go func() {
|
||||
f(m.root)
|
||||
sender.Close()
|
||||
}()
|
||||
// TODO(gri) The design draft doesn't require that we repeat
|
||||
// the type parameters here. Fix the implementation.
|
||||
return &Iterator(K, V){receiver}
|
||||
// return &Iterator{receiver}
|
||||
}
|
||||
|
||||
// Iterator is used to iterate over the map.
|
||||
type Iterator(type K, V) struct {
|
||||
r *chans.Receiver(keyValue(K, V))
|
||||
}
|
||||
|
||||
// Next returns the next key and value pair, and a boolean indicating
|
||||
// whether they are valid or whether we have reached the end.
|
||||
func (it *Iterator(K, V)) Next() (K, V, bool) {
|
||||
keyval, ok := it.r.Next()
|
||||
if !ok {
|
||||
var zerok K
|
||||
var zerov V
|
||||
return zerok, zerov, false
|
||||
}
|
||||
return keyval.key, keyval.val, true
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is like map.go2, but instead if importing chans, it contains
|
||||
// the necessary functionality at the end of the file.
|
||||
|
||||
// Package orderedmap provides an ordered map, implemented as a binary tree.
|
||||
package orderedmap
|
||||
|
||||
// Map is an ordered map.
|
||||
type Map(type K, V) struct {
|
||||
root *node(K, V)
|
||||
compare func(K, K) int
|
||||
}
|
||||
|
||||
// node is the type of a node in the binary tree.
|
||||
type node(type K, V) struct {
|
||||
key K
|
||||
val V
|
||||
left, right *node(K, V)
|
||||
}
|
||||
|
||||
// New returns a new map.
|
||||
func New(type K, V)(compare func(K, K) int) *Map(K, V) {
|
||||
return &Map(K, V){compare: compare}
|
||||
}
|
||||
|
||||
// find looks up key in the map, and returns either a pointer
|
||||
// to the node holding key, or a pointer to the location where
|
||||
// such a node would go.
|
||||
func (m *Map(K, V)) find(key K) **node(K, V) {
|
||||
pn := &m.root
|
||||
for *pn != nil {
|
||||
switch cmp := m.compare(key, (*pn).key); {
|
||||
case cmp < 0:
|
||||
pn = &(*pn).left
|
||||
case cmp > 0:
|
||||
pn = &(*pn).right
|
||||
default:
|
||||
return pn
|
||||
}
|
||||
}
|
||||
return pn
|
||||
}
|
||||
|
||||
// Insert inserts a new key/value into the map.
|
||||
// If the key is already present, the value is replaced.
|
||||
// Returns true if this is a new key, false if already present.
|
||||
func (m *Map(K, V)) Insert(key K, val V) bool {
|
||||
pn := m.find(key)
|
||||
if *pn != nil {
|
||||
(*pn).val = val
|
||||
return false
|
||||
}
|
||||
*pn = &node(K, V){key: key, val: val}
|
||||
return true
|
||||
}
|
||||
|
||||
// Find returns the value associated with a key, or zero if not present.
|
||||
// The found result reports whether the key was found.
|
||||
func (m *Map(K, V)) Find(key K) (V, bool) {
|
||||
pn := m.find(key)
|
||||
if *pn == nil {
|
||||
var zero V // see the discussion of zero values, above
|
||||
return zero, false
|
||||
}
|
||||
return (*pn).val, true
|
||||
}
|
||||
|
||||
// keyValue is a pair of key and value used when iterating.
|
||||
type keyValue(type K, V) struct {
|
||||
key K
|
||||
val V
|
||||
}
|
||||
|
||||
// InOrder returns an iterator that does an in-order traversal of the map.
|
||||
func (m *Map(K, V)) InOrder() *Iterator(K, V) {
|
||||
sender, receiver := chans_Ranger(keyValue(K, V))()
|
||||
var f func(*node(K, V)) bool
|
||||
f = func(n *node(K, V)) bool {
|
||||
if n == nil {
|
||||
return true
|
||||
}
|
||||
// Stop sending values if sender.Send returns false,
|
||||
// meaning that nothing is listening at the receiver end.
|
||||
return f(n.left) &&
|
||||
sender.Send(keyValue(K, V){n.key, n.val}) &&
|
||||
f(n.right)
|
||||
}
|
||||
go func() {
|
||||
f(m.root)
|
||||
sender.Close()
|
||||
}()
|
||||
// TODO(gri) The design draft doesn't require that we repeat
|
||||
// the type parameters here. Fix the implementation.
|
||||
return &Iterator(K, V){receiver}
|
||||
// return &Iterator{receiver}
|
||||
}
|
||||
|
||||
// Iterator is used to iterate over the map.
|
||||
type Iterator(type K, V) struct {
|
||||
r *chans_Receiver(keyValue(K, V))
|
||||
}
|
||||
|
||||
// Next returns the next key and value pair, and a boolean indicating
|
||||
// whether they are valid or whether we have reached the end.
|
||||
func (it *Iterator(K, V)) Next() (K, V, bool) {
|
||||
keyval, ok := it.r.Next()
|
||||
if !ok {
|
||||
var zerok K
|
||||
var zerov V
|
||||
return zerok, zerov, false
|
||||
}
|
||||
return keyval.key, keyval.val, true
|
||||
}
|
||||
|
||||
// chans
|
||||
|
||||
func chans_Ranger(type T)() (*chans_Sender(T), *chans_Receiver(T))
|
||||
|
||||
// A sender is used to send values to a Receiver.
|
||||
type chans_Sender(type T) struct {
|
||||
values chan<- T
|
||||
done <-chan bool
|
||||
}
|
||||
|
||||
func (s *chans_Sender(T)) Send(v T) bool {
|
||||
select {
|
||||
case s.values <- v:
|
||||
return true
|
||||
case <-s.done:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (s *chans_Sender(T)) Close() {
|
||||
close(s.values)
|
||||
}
|
||||
|
||||
type chans_Receiver(type T) struct {
|
||||
values <-chan T
|
||||
done chan<- bool
|
||||
}
|
||||
|
||||
func (r *chans_Receiver(T)) Next() (T, bool) {
|
||||
v, ok := <-r.values
|
||||
return v, ok
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package slices implements various slice algorithms.
|
||||
package slices
|
||||
|
||||
// Map turns a []T1 to a []T2 using a mapping function.
|
||||
func Map(type T1, T2)(s []T1, f func(T1) T2) []T2 {
|
||||
r := make([]T2, len(s))
|
||||
for i, v := range s {
|
||||
r[i] = f(v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Reduce reduces a []T1 to a single value using a reduction function.
|
||||
func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 {
|
||||
r := initializer
|
||||
for _, v := range s {
|
||||
r = f(r, v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Filter filters values from a slice using a filter function.
|
||||
func Filter(type T)(s []T, f func(T) bool) []T {
|
||||
var r []T
|
||||
for _, v := range s {
|
||||
if f(v) {
|
||||
r = append(r, v)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Example uses
|
||||
|
||||
func limiter(x int) byte {
|
||||
switch {
|
||||
case x < 0:
|
||||
return 0
|
||||
default:
|
||||
return byte(x)
|
||||
case x > 255:
|
||||
return 255
|
||||
}
|
||||
}
|
||||
|
||||
var input = []int{-4, 68954, 7, 44, 0, -555, 6945}
|
||||
var limited1 = Map(int, byte)(input, limiter)
|
||||
var limited2 = Map(input, limiter) // using type inference
|
||||
|
||||
func reducer(x float64, y int) float64 {
|
||||
return x + float64(y)
|
||||
}
|
||||
|
||||
var reduced1 = Reduce(int, float64)(input, 0, reducer)
|
||||
var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference
|
||||
var reduced3 = Reduce(input, 1, reducer) // using type inference
|
||||
|
||||
func filter(x int) bool {
|
||||
return x&1 != 0
|
||||
}
|
||||
|
||||
var filtered1 = Filter(int)(input, filter)
|
||||
var filtered2 = Filter(input, filter) // using type inference
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file contains basic generic code snippets.
|
||||
|
||||
package p
|
||||
|
||||
// type parameter lists
|
||||
type _(type) struct{}
|
||||
type B(type P) struct{}
|
||||
type _(type P interface{}) struct{}
|
||||
type _(type P B) struct{}
|
||||
type _(type P B(P)) struct{}
|
||||
|
||||
type _(type A, B, C) struct{}
|
||||
type _(type A, B, C B) struct{}
|
||||
type _(type A, B, C B(A, B, C)) struct{}
|
||||
type _(type A1, A2 B1, A3 B2, A4, A5, A6 B3) struct{}
|
||||
|
||||
type _(type A interface{}) struct{}
|
||||
type _(type A, B interface{ m() }) struct{}
|
||||
|
||||
type _(type A, B, C) struct{}
|
||||
|
||||
// in functions
|
||||
func _(type)()
|
||||
func _(type P)()
|
||||
func _(type P interface{})()
|
||||
func _(type P B)()
|
||||
func _(type P B(P))()
|
||||
|
||||
// in methods
|
||||
func (T) _(type)()
|
||||
func (T) _(type P)()
|
||||
func (T) _(type P interface{})()
|
||||
func (T) _(type P B)()
|
||||
func (T) _(type P B(P))()
|
||||
|
||||
// type instantiations
|
||||
type _ T(int)
|
||||
|
||||
// in expressions
|
||||
var _ = T(int){}
|
||||
|
||||
// in embedded types
|
||||
type _ struct{ (T(int)) }
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type myInt int
|
||||
|
||||
// Parameterized type declarations
|
||||
|
||||
type T1(type P) P
|
||||
|
||||
type T2(type P) struct {
|
||||
f P
|
||||
g int // int should still be in scope chain
|
||||
}
|
||||
|
||||
type List(type P) []P
|
||||
|
||||
// Alias type declarations cannot have type parameters.
|
||||
type A1( /* ERROR cannot be parameterized */ type P) = P /* ERROR undeclared */
|
||||
|
||||
// Parameterized type instantiations
|
||||
|
||||
var x int
|
||||
type _ x /* ERROR not a type */ (int)
|
||||
|
||||
type _ int /* ERROR not a generic type */ ()
|
||||
type _ myInt /* ERROR not a generic type */ ()
|
||||
|
||||
// TODO(gri) better error messages
|
||||
type _ T1 /* ERROR got 0 arguments but 1 type parameters */ ()
|
||||
type _ T1(x /* ERROR not a type */ )
|
||||
type _ T1 /* ERROR got 2 arguments but 1 type parameters */ (int, float32)
|
||||
|
||||
var _ T2(int) = T2(int){}
|
||||
|
||||
var _ List(int) = []int{1, 2, 3}
|
||||
var _ List([]int) = [][]int{{1, 2, 3}}
|
||||
var _ List(List(List(int)))
|
||||
|
||||
// Parameterized types containing parameterized types
|
||||
|
||||
type T3(type P) List(P)
|
||||
|
||||
var _ T3(int) = T3(int)(List(int){1, 2, 3})
|
||||
|
||||
// Self-recursive generic types are not permitted
|
||||
|
||||
type self1(type P) self1 /* ERROR illegal cycle */ (P)
|
||||
type self2(type P) *self2(P) // this is ok
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type List(type E) []E
|
||||
var _ List(List(List(int)))
|
||||
var _ List(List(List(int))) = [](List(List(int))){}
|
||||
|
||||
type (
|
||||
T1(type P1) struct {
|
||||
f1 T2(P1, float32)
|
||||
}
|
||||
|
||||
T2(type P2, P3) struct {
|
||||
f2 P2
|
||||
f3 P3
|
||||
}
|
||||
)
|
||||
|
||||
func _() {
|
||||
var x1 T1(int)
|
||||
var x2 T2(int, float32)
|
||||
|
||||
x1.f1.f2 = 0
|
||||
x1.f1 = x2
|
||||
}
|
||||
|
||||
type T3(type P) T1(T2(P, P))
|
||||
|
||||
func _() {
|
||||
var x1 T3(int)
|
||||
var x2 T2(int, int)
|
||||
x1.f1.f2 = x2
|
||||
}
|
||||
|
||||
func f(type P) (x P) List(P) {
|
||||
return List(P){x}
|
||||
}
|
||||
|
||||
var (
|
||||
_ []int = f(0)
|
||||
_ []float32 = f(float32)(10)
|
||||
_ List(complex128) = f(1i)
|
||||
_ [](List(int)) = f(List(int){})
|
||||
_ List(List(int)) = [](List(int)){}
|
||||
_ = [](List(int)){}
|
||||
)
|
||||
|
||||
// Parameterized types with methods
|
||||
|
||||
func (l List(E)) Head() (_ E, _ bool) {
|
||||
if len(l) > 0 {
|
||||
return l[0], true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A test case for instantiating types with other types (extracted from map.go2)
|
||||
|
||||
type Pair(type K) struct {
|
||||
key K
|
||||
}
|
||||
|
||||
type Receiver(type T) struct {
|
||||
values T
|
||||
}
|
||||
|
||||
type Iterator(type K) struct {
|
||||
r Receiver(Pair(K))
|
||||
}
|
||||
|
||||
func Values (type T) (r Receiver(T)) T {
|
||||
return r.values
|
||||
}
|
||||
|
||||
func (it Iterator(K)) Next() K {
|
||||
return Values(Pair(K))(it.r).key
|
||||
}
|
||||
|
||||
// A more complex test case testing type bounds (extracted from linalg.go2 and reduced to essence)
|
||||
|
||||
type NumericAbs(type T) interface {
|
||||
Abs() T
|
||||
}
|
||||
|
||||
func AbsDifference(type T NumericAbs)(x T)
|
||||
|
||||
type OrderedAbs(type T) T
|
||||
|
||||
func (a OrderedAbs(T)) Abs() OrderedAbs(T)
|
||||
|
||||
func OrderedAbsDifference(type T)(x T) {
|
||||
AbsDifference(OrderedAbs(T)(x))
|
||||
}
|
||||
|
||||
// same code, reduced to essence
|
||||
|
||||
func g(type P interface{ m() P })(x P)
|
||||
|
||||
type T4(type P) P
|
||||
|
||||
func (_ T4(P)) m() T4(P)
|
||||
|
||||
func _(type Q)(x Q) {
|
||||
g(T4(Q)(x))
|
||||
}
|
||||
|
||||
// Another test case that caused problems in the past
|
||||
|
||||
type T5(type _ interface { a() }, _ interface{}) struct{}
|
||||
|
||||
type A(type P) struct{ x P }
|
||||
|
||||
func (_ A(P)) a() {}
|
||||
|
||||
var _ T5(A(int), int)
|
||||
|
||||
// Invoking methods with parameterized receiver types uses
|
||||
// type inference to determine the actual type arguments matching
|
||||
// the receiver type parameters from the actual receiver argument.
|
||||
// Go does implicit address-taking and dereferenciation depending
|
||||
// on the actual receiver and the method's receiver type. To make
|
||||
// type inference work, the type-checker matches "pointer-ness"
|
||||
// of the actual receiver and the method's receiver type.
|
||||
// The following tests verify test this mechanism.
|
||||
|
||||
type R1(type A) struct{}
|
||||
func (_ R1(A)) vm()
|
||||
func (_ *R1(A)) pm()
|
||||
|
||||
func _(type T)(r R1(T), p *R1(T)) {
|
||||
r.vm()
|
||||
r.pm()
|
||||
p.vm()
|
||||
p.pm()
|
||||
}
|
||||
|
||||
type R2(type A, B) struct{}
|
||||
func (_ R2(A, B)) vm()
|
||||
func (_ *R2(A, B)) pm()
|
||||
|
||||
func _(type T)(r R2(T, int), p *R2(string, T)) {
|
||||
r.vm()
|
||||
r.pm()
|
||||
p.vm()
|
||||
p.pm()
|
||||
}
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
import "io" // for type assertion tests
|
||||
|
||||
func identity(type T)(x T) T { return x }
|
||||
|
||||
func _(type)(x int) int
|
||||
func _(type T)(T /* ERROR redeclared */ T)()
|
||||
func _(type T, T /* ERROR redeclared */ )()
|
||||
|
||||
func reverse(type T)(list []T) []T {
|
||||
rlist := make([]T, len(list))
|
||||
i := len(list)
|
||||
for _, x := range list {
|
||||
i--
|
||||
rlist[i] = x
|
||||
}
|
||||
return rlist
|
||||
}
|
||||
|
||||
var _ = reverse /* ERROR cannot use generic function reverse */
|
||||
var _ = reverse(int, float32 /* ERROR got 2 type arguments */ ) ([]int{1, 2, 3})
|
||||
var _ = reverse(int)([ /* ERROR cannot use */ ]float32{1, 2, 3})
|
||||
var f = reverse(chan int)
|
||||
var _ = f(0 /* ERROR cannot convert 0 .* to \[\]chan int */ )
|
||||
|
||||
func swap(type A, B)(a A, b B) (B, A) { return b, a }
|
||||
|
||||
var _ = swap /* ERROR single value is expected */ (int, float32)(1, 2)
|
||||
var f32, i = swap(int, float32)(swap(float32, int)(1, 2))
|
||||
var _ float32 = f32
|
||||
var _ int = i
|
||||
|
||||
func swapswap(type A, B)(a A, b B) (A, B) {
|
||||
return swap(B, A)(b, a)
|
||||
}
|
||||
|
||||
type F(type A, B) func(A, B) (B, A)
|
||||
|
||||
func min(type T interface{ type int })(x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
func _(type T interface{type int, float32})(x, y T) bool { return x < y }
|
||||
func _(type T)(x, y T) bool { return x /* ERROR cannot compare */ < y }
|
||||
func _(type T interface{type int, float32, bool})(x, y T) bool { return x /* ERROR cannot compare */ < y }
|
||||
|
||||
func _(type T C1)(x, y T) bool { return x /* ERROR cannot compare */ < y }
|
||||
func _(type T C2)(x, y T) bool { return x < y }
|
||||
|
||||
type C1(type T) interface{}
|
||||
type C2(type T) interface{ type int, float32 }
|
||||
|
||||
func new(type T)() *T {
|
||||
var x T
|
||||
return &x
|
||||
}
|
||||
|
||||
var _ = new /* ERROR cannot use generic function new */
|
||||
var _ *int = new(int)()
|
||||
|
||||
func _(type T)(map[T /* ERROR invalid map key type */]int) // w/o contract we don't know if T is comparable
|
||||
|
||||
func f1(type T1)(struct{T1}) int
|
||||
var _ = f1(int)(struct{T1}{})
|
||||
type T1 = int
|
||||
|
||||
func f2(type t1)(struct{t1; x float32}) int
|
||||
var _ = f2(t1)(struct{t1; x float32}{})
|
||||
type t1 = int
|
||||
|
||||
|
||||
func f3(type A, B, C)(A, struct{x B}, func(A, struct{x B}, *C)) int
|
||||
|
||||
var _ = f3(int, rune, bool)(1, struct{x rune}{}, nil)
|
||||
|
||||
// indexing
|
||||
|
||||
func _(type T) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
func _(type T interface{ type int }) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
func _(type T interface{ type string }) (x T, i int) { _ = x[i] }
|
||||
func _(type T interface{ type []int }) (x T, i int) { _ = x[i] }
|
||||
func _(type T interface{ type [10]int, *[20]int, map[string]int }) (x T, i int) { _ = x[i] }
|
||||
func _(type T interface{ type string, []byte }) (x T, i int) { _ = x[i] }
|
||||
func _(type T interface{ type []int, [1]rune }) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
func _(type T interface{ type string, []rune }) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
|
||||
// slicing
|
||||
// TODO(gri) implement this
|
||||
|
||||
func _(type T interface{ type string }) (x T, i, j, k int) { _ = x /* ERROR not yet implemented */ [i:j:k] }
|
||||
|
||||
// len/cap built-ins
|
||||
|
||||
func _(type T)(x T) { _ = len(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type int })(x T) { _ = len(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type string, []byte, int })(x T) { _ = len(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type string })(x T) { _ = len(x) }
|
||||
func _(type T interface{ type [10]int })(x T) { _ = len(x) }
|
||||
func _(type T interface{ type []byte })(x T) { _ = len(x) }
|
||||
func _(type T interface{ type map[int]int })(x T) { _ = len(x) }
|
||||
func _(type T interface{ type chan int })(x T) { _ = len(x) }
|
||||
func _(type T interface{ type string, []byte, chan int })(x T) { _ = len(x) }
|
||||
|
||||
func _(type T)(x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type int })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type string, []byte, int })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type string })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type [10]int })(x T) { _ = cap(x) }
|
||||
func _(type T interface{ type []byte })(x T) { _ = cap(x) }
|
||||
func _(type T interface{ type map[int]int })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _(type T interface{ type chan int })(x T) { _ = cap(x) }
|
||||
func _(type T interface{ type []byte, chan int })(x T) { _ = cap(x) }
|
||||
|
||||
// range iteration
|
||||
|
||||
func _(type T interface{})(x T) {
|
||||
for range x /* ERROR cannot range */ {}
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, []string })(x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i }
|
||||
for i, e := range x /* ERROR must have the same element type */ { _ = i }
|
||||
for _, e := range x /* ERROR must have the same element type */ {}
|
||||
var e rune
|
||||
_ = e
|
||||
for _, (e) = range x /* ERROR must have the same element type */ {}
|
||||
}
|
||||
|
||||
|
||||
func _(type T interface{ type string, []rune, map[int]rune })(x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x { _ = i; _ = e }
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, []rune, map[string]rune })(x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x /* ERROR must have the same key type */ { _ = e }
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, chan int })(x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, chan<-int })(x T) {
|
||||
for i := range x /* ERROR send-only channel */ { _ = i }
|
||||
}
|
||||
|
||||
// type inference checks
|
||||
|
||||
var _ = new() /* ERROR cannot infer T */
|
||||
|
||||
func f4(type A, B, C)(A, B) C
|
||||
|
||||
var _ = f4(1, 2) /* ERROR cannot infer C */
|
||||
var _ = f4(int, float32, complex128)(1, 2)
|
||||
|
||||
func f5(type A, B, C)(A, []*B, struct{f []C}) int
|
||||
|
||||
var _ = f5(int, float32, complex128)(0, nil, struct{f []complex128}{})
|
||||
var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer
|
||||
var _ = f5(0, []*float32{new(float32)()}, struct{f []complex128}{})
|
||||
|
||||
func f6(type A)(A, []A) int
|
||||
|
||||
var _ = f6(0, nil)
|
||||
|
||||
func f6nil(type A)(A) int
|
||||
|
||||
var _ = f6nil(nil) // ERROR cannot infer
|
||||
|
||||
// type inference with variadic functions
|
||||
|
||||
func f7(type T)(...T) T
|
||||
|
||||
var _ int = f7() /* ERROR cannot infer T */
|
||||
var _ int = f7(1)
|
||||
var _ int = f7(1, 2)
|
||||
var _ int = f7([]int{}...)
|
||||
var _ int = f7 /* ERROR cannot use */ ([]float64{}...)
|
||||
var _ float64 = f7([]float64{}...)
|
||||
var _ = f7(float64)(1, 2.3)
|
||||
var _ = f7(float64(1), 2.3)
|
||||
var _ = f7(1, 2.3 /* ERROR does not match */ )
|
||||
var _ = f7(1.2, 3 /* ERROR does not match */ )
|
||||
|
||||
func f8(type A, B)(A, B, ...B) int
|
||||
|
||||
var _ = f8(1) /* ERROR not enough arguments */
|
||||
var _ = f8(1, 2.3)
|
||||
var _ = f8(1, 2.3, 3.4, 4.5)
|
||||
var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ )
|
||||
var _ = f8(int, float64)(1, 2.3, 3.4, 4)
|
||||
|
||||
var _ = f8(int, float64)(0, 0, nil...) // test case for #18268
|
||||
|
||||
// init functions cannot have type parameters
|
||||
|
||||
func init() {}
|
||||
func init(/* ERROR func init must have no type parameters */ type)() {}
|
||||
func init(/* ERROR func init must have no type parameters */ type P)() {}
|
||||
|
||||
type T struct {}
|
||||
|
||||
func (T) m1() {}
|
||||
// Experimental: We allow method type parameters.
|
||||
func (T) m2(type)() {}
|
||||
func (T) m3(type P)() {}
|
||||
|
||||
// type inference across parameterized types
|
||||
|
||||
type S1(type P) struct { f P }
|
||||
|
||||
func f9(type P)(x S1(P))
|
||||
|
||||
func _() {
|
||||
f9(int)(S1(int){42})
|
||||
f9(S1(int){42})
|
||||
}
|
||||
|
||||
type S2(type A, B, C) struct{}
|
||||
|
||||
func f10(type X, Y, Z)(a S2(X, int, Z), b S2(X, Y, bool))
|
||||
|
||||
func _(type P)() {
|
||||
f10(int, float32, string)(S2(int, int, string){}, S2(int, float32, bool){})
|
||||
f10(S2(int, int, string){}, S2(int, float32, bool){})
|
||||
f10(S2(P, int, P){}, S2(P, float32, bool){})
|
||||
}
|
||||
|
||||
// corner case for type inference
|
||||
// (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic)
|
||||
|
||||
func f11(type T)()
|
||||
|
||||
func _() {
|
||||
f11(int)()
|
||||
}
|
||||
|
||||
// the previous example was extracted from
|
||||
|
||||
func f12(type T interface{m() T})()
|
||||
|
||||
type A(type T) T
|
||||
|
||||
func (a A(T)) m() A(T)
|
||||
|
||||
func _(type T)() {
|
||||
f12(A(T))()
|
||||
}
|
||||
|
||||
// method expressions
|
||||
|
||||
func (_ S1(P)) m()
|
||||
|
||||
func _() {
|
||||
m := S1(int).m
|
||||
m(struct { f int }{42})
|
||||
}
|
||||
|
||||
func _(type T) (x T) {
|
||||
m := S1(T).m
|
||||
m(S1(T){x})
|
||||
}
|
||||
|
||||
// type parameters in methods (generalization)
|
||||
|
||||
type R0 struct{}
|
||||
|
||||
func (R0) _(type T)(x T)
|
||||
func (R0 /* ERROR invalid receiver */ ) _(type R0)() // scope of type parameters starts at "func"
|
||||
|
||||
type R1(type A, B) struct{}
|
||||
|
||||
func (_ R1(A, B)) m0(A, B)
|
||||
func (_ R1(A, B)) m1(type T)(A, B, T) T
|
||||
func (_ R1 /* ERROR not a generic type */ (R1, _)) _()
|
||||
func (_ R1(A, B)) _(type A /* ERROR redeclared */ )(B)
|
||||
|
||||
func _() {
|
||||
var r R1(int, string)
|
||||
r.m1(rune)(42, "foo", 'a')
|
||||
r.m1(rune)(42, "foo", 1.2 /* ERROR truncated to rune */)
|
||||
r.m1(42, "foo", 1.2) // using type inferrence
|
||||
var _ float64 = r.m1(42, "foo", 1.2)
|
||||
}
|
||||
|
||||
type I1(type A) interface {
|
||||
m1(A)
|
||||
}
|
||||
|
||||
var _ I1(int) = r1(int){}
|
||||
|
||||
type r1(type T) struct{}
|
||||
|
||||
func (_ r1(T)) m1(T)
|
||||
|
||||
type I2(type A, B) interface {
|
||||
m1(A)
|
||||
m2(A) B
|
||||
}
|
||||
|
||||
var _ I2(int, float32) = R2(int, float32){}
|
||||
|
||||
type R2(type P, Q) struct{}
|
||||
|
||||
func (_ R2(X, Y)) m1(X)
|
||||
func (_ R2(X, Y)) m2(X) Y
|
||||
|
||||
// type assertions and type switches over generic types
|
||||
|
||||
// ReadByte1 corresponds to the ReadByte example in the contracts draft design.
|
||||
func ReadByte1(type T io.Reader)(r T) (byte, error) {
|
||||
if br, ok := r.(io.ByteReader); ok {
|
||||
return br.ReadByte()
|
||||
}
|
||||
var b [1]byte
|
||||
_, err := r.Read(b[:])
|
||||
return b[0], err
|
||||
}
|
||||
|
||||
// ReadBytes2 is like ReadByte1 but uses a type switch instead.
|
||||
func ReadByte2(type T io.Reader)(r T) (byte, error) {
|
||||
switch br := r.(type) {
|
||||
case io.ByteReader:
|
||||
return br.ReadByte()
|
||||
}
|
||||
var b [1]byte
|
||||
_, err := r.Read(b[:])
|
||||
return b[0], err
|
||||
}
|
||||
|
||||
// type assertions and type switches over generic types are strict
|
||||
type I3 interface {
|
||||
m(int)
|
||||
}
|
||||
|
||||
type I4 interface {
|
||||
m() int // different signature from I3.m
|
||||
}
|
||||
|
||||
func _(type T I3)(x I3, p T) {
|
||||
// type assertions and type switches over interfaces are not strict
|
||||
_ = x.(I4)
|
||||
switch x.(type) {
|
||||
case I4:
|
||||
}
|
||||
|
||||
// type assertions and type switches over generic types are strict
|
||||
_ = p /* ERROR cannot have dynamic type I4 */.(I4)
|
||||
switch p.(type) {
|
||||
case I4 /* ERROR cannot have dynamic type I4 */ :
|
||||
}
|
||||
}
|
||||
|
||||
// error messages related to type bounds mention those bounds
|
||||
type C(type P) interface{}
|
||||
|
||||
func _(type P C) (x P) {
|
||||
x.m /* ERROR x.m undefined */ ()
|
||||
}
|
||||
|
||||
type I interface {}
|
||||
|
||||
func _(type P I) (x P) {
|
||||
x.m /* ERROR interface I has no method m */ ()
|
||||
}
|
||||
|
||||
func _(type P interface{}) (x P) {
|
||||
x.m /* ERROR type bound for P has no method m */ ()
|
||||
}
|
||||
|
||||
func _(type P) (x P) {
|
||||
x.m /* ERROR type bound for P has no method m */ ()
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// errorcheck
|
||||
// compile
|
||||
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
|
@ -12,10 +12,16 @@ type T struct {
|
|||
y (int)
|
||||
int
|
||||
*float64
|
||||
/*
|
||||
// not legal according to spec
|
||||
(complex128) // ERROR "non-declaration|expected|parenthesize"
|
||||
(*string) // ERROR "non-declaration|expected|parenthesize"
|
||||
*(bool) // ERROR "non-declaration|expected|parenthesize"
|
||||
*/
|
||||
// generic Go permits (and in some cases requires) parentheses for embedded types
|
||||
(complex128)
|
||||
(*string)
|
||||
*(bool)
|
||||
}
|
||||
|
||||
// legal according to spec
|
||||
|
|
|
|||
Loading…
Reference in New Issue