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:
Robert Griesemer 2020-05-01 20:58:32 -07:00
parent bc3ba78503
commit 70f1138c60
13 changed files with 1322 additions and 138 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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")

View File

@ -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)
}

View File

@ -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)))
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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)) }

View File

@ -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

View File

@ -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()
}

View File

@ -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 */ ()
}

View File

@ -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