mirror of https://github.com/golang/go.git
go/types: fix collection of receiver type parameters
... and various related smaller fixes We can now type-check the slices, chans, and maps examples from the design doc (with the maps example prodcing an error because importing chans doesn't work yet). Progress! Change-Id: Ifc00359a9a1cdad3bde1659a7de2028ac2544469
This commit is contained in:
parent
3c6943daac
commit
fbff5cc915
|
|
@ -999,6 +999,10 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
func (f *FuncDecl) IsMethod() bool {
|
||||
return f.Recv.NumFields() != 0
|
||||
}
|
||||
|
||||
// Pos and End implementations for declaration nodes.
|
||||
|
||||
func (d *BadDecl) Pos() token.Pos { return d.From }
|
||||
|
|
|
|||
|
|
@ -522,7 +522,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
// _before_ calling NewMethodSet: LookupFieldOrMethod completes
|
||||
// any incomplete interfaces so they are available to NewMethodSet
|
||||
// (which assumes that interfaces have been completed already).
|
||||
typ := unpack(x.typ)
|
||||
typ := x.typ
|
||||
if x.mode == variable {
|
||||
// If typ is not an (unnamed) pointer or an interface,
|
||||
// use *typ instead, because the method set of *typ
|
||||
|
|
|
|||
|
|
@ -105,6 +105,11 @@ var tests = [][]string{
|
|||
{"testdata/typeinst.go2"},
|
||||
{"testdata/typeinst2.go2"},
|
||||
{"testdata/contracts.go2"},
|
||||
|
||||
// Go 2 examples from design doc
|
||||
{"testdata/slices.go2"},
|
||||
{"testdata/chans.go2"},
|
||||
{"testdata/map.go2"},
|
||||
}
|
||||
|
||||
var fset = token.NewFileSet()
|
||||
|
|
|
|||
|
|
@ -265,8 +265,6 @@ func (check *Checker) satisfyContract(contr *Contract, targs []Type) bool {
|
|||
panic("unimplemented")
|
||||
}
|
||||
// use interface type of type parameter, if any
|
||||
// TODO(gri) is this the correct place for this? (why not in missinMethod?)
|
||||
targ = unpack(targ)
|
||||
// targ must implement iface
|
||||
if m, _ := check.missingMethod(targ, iface, true); m != nil {
|
||||
// check.dump("missing %s (%s, %s)", m, targ, iface)
|
||||
|
|
@ -276,14 +274,3 @@ func (check *Checker) satisfyContract(contr *Contract, targs []Type) bool {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
// unpack returns the interface type of a type parameter,
|
||||
// otherwise it just returns the argument type.
|
||||
// TODO(gri) This function is currently uses if a few places.
|
||||
// Need to determine if there's a better way to handle this.
|
||||
func unpack(typ Type) Type {
|
||||
if tpar, _ := typ.(*TypeParam); tpar != nil {
|
||||
return tpar.Interface()
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
|
|
|||
|
|
@ -617,16 +617,20 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
|
|||
}
|
||||
|
||||
for _, name := range f.Names {
|
||||
tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
|
||||
NewTypeParam(tpar, len(tparams), contr) // assigns type to tpar as a side-effect
|
||||
check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) verify scope pos is correct
|
||||
tparams = append(tparams, tpar)
|
||||
tparams = append(tparams, check.declareTypeParam(name, len(tparams), contr))
|
||||
}
|
||||
}
|
||||
|
||||
return tparams
|
||||
}
|
||||
|
||||
func (check *Checker) declareTypeParam(name *ast.Ident, index int, contr *Contract) *TypeName {
|
||||
tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
|
||||
NewTypeParam(tpar, index, contr) // assigns type to tpar as a side-effect
|
||||
check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
|
||||
return tpar
|
||||
}
|
||||
|
||||
func (check *Checker) addMethodDecls(obj *TypeName) {
|
||||
// get associated methods
|
||||
// (Checker.collectObjects only collects methods with non-blank names;
|
||||
|
|
@ -694,18 +698,31 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
|
|||
assert(check.iota == nil)
|
||||
|
||||
fdecl := decl.fdecl
|
||||
if fdecl.TParams != nil {
|
||||
check.openScope(fdecl, "type parameters")
|
||||
if fdecl.IsMethod() {
|
||||
_, _, tparams := check.unpackRecv(fdecl.Recv.List[0].Type, true)
|
||||
if len(tparams) > 0 {
|
||||
// TODO(gri) need to provide contract
|
||||
// (check that number of parameters match is done when type-checking the receiver expression)
|
||||
check.openScope(fdecl, "receiver type parameters")
|
||||
defer check.closeScope()
|
||||
for i, name := range tparams {
|
||||
obj.tparams = append(obj.tparams, check.declareTypeParam(name, i, nil))
|
||||
}
|
||||
}
|
||||
} else if fdecl.TParams != nil {
|
||||
check.openScope(fdecl, "function type parameters")
|
||||
defer check.closeScope()
|
||||
obj.tparams = check.collectTypeParams(fdecl.TParams)
|
||||
}
|
||||
|
||||
sig := new(Signature)
|
||||
obj.typ = sig // guard against cycles
|
||||
check.funcType(sig, fdecl.Recv, fdecl.Type)
|
||||
sig.tparams = obj.tparams
|
||||
|
||||
if fdecl.TParams != nil {
|
||||
check.closeScope()
|
||||
if !fdecl.IsMethod() {
|
||||
// only functions can have type parameters that need to be passed
|
||||
// (the obj.tparams for methods are the receiver parameters)
|
||||
// TODO(gri) remove the need for storing tparams in signatures
|
||||
sig.tparams = obj.tparams
|
||||
}
|
||||
|
||||
// function body must be type-checked after global declarations
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
|||
return // blank fields/methods are never found
|
||||
}
|
||||
|
||||
typ, isPtr := deref(T)
|
||||
typ, isPtr := derefUnpack(T)
|
||||
|
||||
// *typ where typ is an interface has no methods.
|
||||
if isPtr && IsInterface(typ) {
|
||||
|
|
@ -164,7 +164,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
|||
// this depth, f.typ appears multiple times at the next
|
||||
// depth.
|
||||
if obj == nil && f.embedded {
|
||||
typ, isPtr := deref(f.typ)
|
||||
typ, isPtr := derefUnpack(f.typ)
|
||||
// TODO(gri) optimization: ignore types that can't
|
||||
// have fields or methods (only Named, Struct, and
|
||||
// Interface types need to be considered).
|
||||
|
|
@ -356,6 +356,20 @@ func deref(typ Type) (Type, bool) {
|
|||
return typ, false
|
||||
}
|
||||
|
||||
// derefUnpack is like deref but it also unpacks type parameters
|
||||
// and parameterized types.
|
||||
func derefUnpack(typ Type) (Type, bool) {
|
||||
typ, ptr := deref(typ)
|
||||
// TODO(gri) do we need to iterate/recurse here for unpacking?
|
||||
switch t := typ.(type) {
|
||||
case *Parameterized:
|
||||
typ = t.tname.typ
|
||||
case *TypeParam:
|
||||
typ = t.Interface()
|
||||
}
|
||||
return typ, ptr
|
||||
}
|
||||
|
||||
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
|
||||
// (named or unnamed) struct and returns its base. Otherwise it returns typ.
|
||||
func derefStructPtr(typ Type) Type {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func NewMethodSet(T Type) *MethodSet {
|
|||
// method set up to the current depth, allocated lazily
|
||||
var base methodSet
|
||||
|
||||
typ, isPtr := deref(T)
|
||||
typ, isPtr := derefUnpack(T)
|
||||
|
||||
// *typ where typ is an interface has no methods.
|
||||
if isPtr && IsInterface(typ) {
|
||||
|
|
@ -141,7 +141,7 @@ func NewMethodSet(T Type) *MethodSet {
|
|||
// this depth, f.Type appears multiple times at the next
|
||||
// depth.
|
||||
if f.embedded {
|
||||
typ, isPtr := deref(f.typ)
|
||||
typ, isPtr := derefUnpack(f.typ)
|
||||
// TODO(gri) optimization: ignore types that can't
|
||||
// have fields or methods (only Named, Struct, and
|
||||
// Interface types need to be considered).
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ func (*Var) isDependency() {} // a variable may be a dependency of an initializa
|
|||
type Func struct {
|
||||
object
|
||||
hasPtrRecv bool // only valid for methods that don't have a type yet
|
||||
tparams []*TypeName // type parameters from left to right; or nil
|
||||
tparams []*TypeName // type parameters from left to right (rcvr parameters for methods); or nil
|
||||
}
|
||||
|
||||
// NewFunc returns a new function with the given signature, representing
|
||||
|
|
@ -336,9 +336,6 @@ func (obj *Func) FullName() string {
|
|||
// Scope returns the scope of the function's body block.
|
||||
func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
|
||||
|
||||
// IsParameterized reports whether obj is a parameterized function.
|
||||
func (obj *Func) IsParameterized() bool { return len(obj.tparams) > 0 }
|
||||
|
||||
func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
|
||||
|
||||
// A Label represents a declared label.
|
||||
|
|
@ -398,6 +395,20 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
|||
case *Func:
|
||||
buf.WriteString("func ")
|
||||
writeFuncName(buf, obj, qf)
|
||||
// Func.tparams is used for functions and methods; but for methods
|
||||
// these are the receiver parameters. Don't print them twice.
|
||||
// TODO(gri) receiver and type parameters should be in the Func
|
||||
// object, not the signature. That should simplify things throughout.
|
||||
if len(obj.tparams) > 0 && (typ == nil || typ.(*Signature).recv == nil) {
|
||||
buf.WriteString("(type ")
|
||||
for i, tname := range obj.tparams {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(tname.name)
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
if typ != nil {
|
||||
WriteSignature(buf, typ.(*Signature), qf)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ func (check *Checker) collectObjects() {
|
|||
case *ast.FuncDecl:
|
||||
name := d.Name.Name
|
||||
obj := NewFunc(d.Name.Pos(), pkg, name, nil)
|
||||
if d.Recv == nil || len(d.Recv.List) == 0 {
|
||||
if !d.IsMethod() {
|
||||
// regular function
|
||||
if d.Recv != nil {
|
||||
check.errorf(d.Recv.Pos(), "method is missing receiver")
|
||||
|
|
@ -440,14 +440,7 @@ func (check *Checker) collectObjects() {
|
|||
// - if the receiver type is parameterized but we don't need the parameters, we permit leaving them away
|
||||
// - this is a effectively a declaration, and thus a receiver type parameter may be the blank identifier (_)
|
||||
// - since methods cannot have other type parameters, we store receiver type parameters where function type parameters would be
|
||||
// TODO(gri) move this into decl phase? (like we did for type and func type parameters?)
|
||||
ptr, recv, tparams := check.unpackRecv(d.Recv.List[0].Type)
|
||||
if tparams != nil {
|
||||
scope := NewScope(pkg.scope, d.Pos(), d.End(), "receiver type parameters")
|
||||
check.recordScope(d, scope)
|
||||
obj.tparams = check.declareTypeParams(scope, tparams)
|
||||
}
|
||||
|
||||
ptr, recv, _ := check.unpackRecv(d.Recv.List[0].Type, false)
|
||||
// (Methods with invalid receiver cannot be associated to a type, and
|
||||
// methods with blank _ names are never found; no need to collect any
|
||||
// of them. They will still be type-checked with all the other functions.)
|
||||
|
|
@ -504,53 +497,49 @@ func (check *Checker) collectObjects() {
|
|||
}
|
||||
}
|
||||
|
||||
func (check *Checker) declareTypeParams(scope *Scope, list []*ast.Ident) []*TypeName {
|
||||
tparams := make([]*TypeName, len(list))
|
||||
for i, name := range list {
|
||||
tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
|
||||
NewTypeParam(tpar, i, nil) // assigns type to tpar as a side-effect
|
||||
check.declare(scope, name, tpar, scope.pos)
|
||||
tparams[i] = tpar
|
||||
}
|
||||
return tparams
|
||||
}
|
||||
|
||||
// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether
|
||||
// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its
|
||||
// type parameters, if any. If rname is nil, the receiver is unusable (i.e., the source
|
||||
// has a bug which we cannot easily work aound with).
|
||||
func (check *Checker) unpackRecv(rtyp ast.Expr) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) {
|
||||
// unparen and dereference
|
||||
rtyp = unparen(rtyp)
|
||||
if ptyp, _ := rtyp.(*ast.StarExpr); ptyp != nil {
|
||||
ptr = true
|
||||
rtyp = unparen(ptyp.X)
|
||||
}
|
||||
|
||||
// extract type parameters, if any
|
||||
if ptyp, _ := rtyp.(*ast.CallExpr); ptyp != nil {
|
||||
rtyp = ptyp.Fun
|
||||
tparams = make([]*ast.Ident, len(ptyp.Args))
|
||||
for i, arg := range ptyp.Args {
|
||||
var par *ast.Ident
|
||||
switch arg := arg.(type) {
|
||||
case *ast.Ident:
|
||||
par = arg
|
||||
case *ast.BadExpr:
|
||||
// ignore - error already reported by parser
|
||||
case nil:
|
||||
check.invalidAST(ptyp.Pos(), "parameterized reveiver contains nil parameters")
|
||||
default:
|
||||
check.errorf(arg.Pos(), "%s is not a valid receiver type parameter declaration", arg)
|
||||
}
|
||||
if par == nil {
|
||||
par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
|
||||
}
|
||||
tparams[i] = par
|
||||
// type parameters, if any. The type parameters are only unpacked if unpackParams is
|
||||
// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we
|
||||
// cannot easily work aound with).
|
||||
func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) {
|
||||
L: // unpack receiver type
|
||||
for {
|
||||
switch t := rtyp.(type) {
|
||||
case *ast.ParenExpr:
|
||||
rtyp = t.X
|
||||
case *ast.StarExpr:
|
||||
rtyp = t.X
|
||||
default:
|
||||
break L
|
||||
}
|
||||
}
|
||||
|
||||
// extract receiver name
|
||||
// unpack type parameters, if any
|
||||
if ptyp, _ := rtyp.(*ast.CallExpr); ptyp != nil {
|
||||
rtyp = ptyp.Fun
|
||||
if unpackParams {
|
||||
for _, arg := range ptyp.Args {
|
||||
var par *ast.Ident
|
||||
switch arg := arg.(type) {
|
||||
case *ast.Ident:
|
||||
par = arg
|
||||
case *ast.BadExpr:
|
||||
// ignore - error already reported by parser
|
||||
case nil:
|
||||
check.invalidAST(ptyp.Pos(), "parameterized receiver contains nil parameters")
|
||||
default:
|
||||
check.errorf(arg.Pos(), "receiver type parameter %s must be an identifier", arg)
|
||||
}
|
||||
if par == nil {
|
||||
par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
|
||||
}
|
||||
tparams = append(tparams, par)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unpack receiver name
|
||||
if name, _ := rtyp.(*ast.Ident); name != nil {
|
||||
rname = name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ func (check *Checker) inst(tname *TypeName, targs []Type) (res Type) {
|
|||
// to prove that this is always the case and then we don't need this extra
|
||||
// argument anymore.
|
||||
func (check *Checker) subst(typ Type, tparams []*TypeName, targs []Type) Type {
|
||||
// check.dump("%s: tparams %d, targs %d", typ, len(tparams), len(targs))
|
||||
assert(len(tparams) == len(targs))
|
||||
if len(tparams) == 0 {
|
||||
return typ
|
||||
|
|
@ -139,9 +140,11 @@ func (s *subster) typ(typ Type) (res Type) {
|
|||
//s.check.dump("- finished %s", tname)
|
||||
// instantiate custom methods as necessary
|
||||
for _, m := range t.methods {
|
||||
// methods may not have a fully set up signature yet
|
||||
s.check.objDecl(m, nil)
|
||||
sig := s.check.subst(m.typ, m.tparams, s.targs).(*Signature)
|
||||
m1 := NewFunc(m.pos, m.pkg, m.name, sig)
|
||||
//s.check.dump("%s: method %s => %s", name, m, m1)
|
||||
// s.check.dump("%s: method %s => %s", name, m, m1)
|
||||
named.methods = append(named.methods, m1)
|
||||
}
|
||||
// TODO(gri) update the method receivers?
|
||||
|
|
|
|||
|
|
@ -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,113 @@
|
|||
// 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) &&
|
||||
// TODO
|
||||
// sender.Send(keyValue(K, V){n.key, n.val}) &&
|
||||
f(n.right)
|
||||
}
|
||||
go func() {
|
||||
f(m.root)
|
||||
sender.Close()
|
||||
}()
|
||||
// TODO(gri) The design doc doensn'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
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ func reducer(x float64, y int) float64 {
|
|||
|
||||
var reduced1 = Reduce(int, float64)(input, 0, reducer)
|
||||
var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference
|
||||
var reduced2 = Reduce(input, 1, reducer) // using type inference
|
||||
var reduced3 = Reduce(input, 1, reducer) // using type inference
|
||||
|
||||
func filter(x int) bool {
|
||||
return x&1 != 0
|
||||
|
|
|
|||
|
|
@ -1,23 +1,13 @@
|
|||
// 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
|
||||
|
||||
contract Stringer(T) {
|
||||
T String() string
|
||||
type S(type T) struct {
|
||||
f T
|
||||
}
|
||||
|
||||
type List(type T Stringer) struct{
|
||||
data T
|
||||
link *List(T)
|
||||
}
|
||||
|
||||
type MyData string
|
||||
|
||||
func (s MyData) String() string { return string(s) }
|
||||
|
||||
var _ List(MyData)
|
||||
|
||||
func _(type T Stringer)(s []T) (r []string) {
|
||||
for _, x := range s {
|
||||
r = append(r, x.String())
|
||||
}
|
||||
return
|
||||
func (r S(T)) m() T {
|
||||
return r.f
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ package p
|
|||
|
||||
type myInt int
|
||||
|
||||
// Parametrized type declarations
|
||||
// Parameterized type declarations
|
||||
|
||||
type T1(type P) P
|
||||
|
||||
|
|
@ -17,10 +17,10 @@ type T2(type P) struct {
|
|||
|
||||
type List(type P) []P
|
||||
|
||||
// Alias type declarations cannot have parameters.
|
||||
// Alias type declarations cannot have type parameters.
|
||||
type A1( /* ERROR cannot be parameterized */ type P) = P /* ERROR undeclared */
|
||||
|
||||
// Parametrized type instantiations
|
||||
// Parameterized type instantiations
|
||||
|
||||
var x int
|
||||
type _ x /* ERROR not a type */ (int)
|
||||
|
|
@ -39,7 +39,7 @@ var _ List(int) = []int{1, 2, 3}
|
|||
var _ List([]int) = [][]int{{1, 2, 3}}
|
||||
var _ List(List(List(int)))
|
||||
|
||||
// Parametrized types containing parametrized types
|
||||
// Parameterized types containing parameterized types
|
||||
|
||||
type T3(type P) List(P)
|
||||
|
||||
|
|
|
|||
|
|
@ -50,3 +50,9 @@ var (
|
|||
|
||||
// Parameterized types with methods
|
||||
|
||||
func (l List(E)) Head() (_ E, _ bool) {
|
||||
if len(l) > 0 {
|
||||
return l[0], true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ var _ = f8(int, float64)(1, 2.3, 3.4, 4)
|
|||
|
||||
var _ = f8(int, float64)(0, 0, nil...) // test case for #18268
|
||||
|
||||
// init function and methods cannot have type parameters
|
||||
// init functions and methods cannot have type parameters
|
||||
|
||||
func init() {}
|
||||
func init(/* ERROR func init must have no type parameters */ type)() {}
|
||||
|
|
|
|||
|
|
@ -348,17 +348,6 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
|
|||
}
|
||||
|
||||
func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
|
||||
if len(sig.tparams) > 0 {
|
||||
buf.WriteString("(type ")
|
||||
for i, tname := range sig.tparams {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(tname.name)
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
|
||||
writeTuple(buf, sig.params, sig.variadic, qf, visited)
|
||||
|
||||
n := sig.results.Len()
|
||||
|
|
|
|||
Loading…
Reference in New Issue