mirror of https://github.com/golang/go.git
go/types: add testdata/map2.go2, update README
Change-Id: I5a859fe3298998810ba56f3b445fae8e1d177995
This commit is contained in:
parent
5891f8c720
commit
0ac0b8518c
|
|
@ -2,7 +2,7 @@ This code contains changes to go/types and the go/* support libraries
|
|||
to type-check generic code as outlined in the latest contracts proposal
|
||||
and presented by Ian Lance Taylor at GopherCon 2019 in San Diego.
|
||||
|
||||
CAUTION: EARLY PROTOTYPE. A LOT IS STILL MISSING. THERE ARE MANY BUGS.
|
||||
CAUTION: EARLY PROTOTYPE. MISSING PIECES. THERE ARE BUGS.
|
||||
|
||||
Read and use the code at your own risk.
|
||||
|
||||
|
|
@ -10,31 +10,26 @@ That said, the go/parser and go/ast changes are working and pass tests
|
|||
including all the larger examples in the latest contracts design doc.
|
||||
Look for the *.go2 files in go/parser/testdata.
|
||||
|
||||
gofmt does not work with parameterized code yet.
|
||||
gofmt works only partly with parameterized code.
|
||||
|
||||
The type-checker is starting to work but has still many problems.
|
||||
The type-checker is starting to work but is not complete.
|
||||
I will update this CL from time to time as progress happens.
|
||||
|
||||
Specifically, the following pieces (and more) are missing from type-
|
||||
checking or lead to unexpected behavior:
|
||||
|
||||
- Importing of packages with type parameters or contracts.
|
||||
- Type-checking of contracts and type parameter lists with contracts.
|
||||
For instance, because contracts are not yet type-checked, maps where
|
||||
the key type is a type parameter will lead to an error because the
|
||||
type checker doesn't know whether the key type is comparable or not.
|
||||
- Parameterized alias types.
|
||||
- Type instantiation is not always working as expected, leading to
|
||||
some odd error messages.
|
||||
- Methods with parameterized receiver types have only recently started
|
||||
to work; there are a few issues around them with proper type
|
||||
instantiation.
|
||||
- Type-checking of contracts is limited to contracts with methods.
|
||||
- Methods with parameterized receiver types are not implemented yet.
|
||||
|
||||
The following is "working" (as in: can be type-checked without errors):
|
||||
|
||||
- Declaration and use of simple parameterized types without contracts.
|
||||
- Declaration and use (calls) of simple parameterized functions without
|
||||
contracts, including type inference from function arguments.
|
||||
- Declaration and use of parameterized types.
|
||||
- Declaration and use (calls) of parameterized functions,
|
||||
including type inference from function arguments.
|
||||
- Some larger tests pass mostly (see testdata/*.go2 files).
|
||||
|
||||
Some code may look like it's working, but it may simply not do anything.
|
||||
|
||||
Error messages, where present, are in usable condition but expect
|
||||
them to be significantly better in a more complete implementation.
|
||||
|
|
@ -42,7 +37,7 @@ them to be significantly better in a more complete implementation.
|
|||
To play with this prototype:
|
||||
|
||||
- Cherry-pick this CL on top of tip (the cherry-pick was tested with
|
||||
tip at 919594830f17):
|
||||
tip at 4983a0b75b40):
|
||||
|
||||
git fetch "https://go.googlesource.com/go" ... && git cherry-pick FETCH_HEAD
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ var tests = [][]string{
|
|||
{"testdata/slices.go2"},
|
||||
{"testdata/chans.go2"},
|
||||
{"testdata/map.go2"},
|
||||
{"testdata/map2.go2"},
|
||||
}
|
||||
|
||||
var fset = token.NewFileSet()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
// 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 /* ERROR not implemented */ .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 /* ERROR not implemented */ .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 /* ERROR not implemented */ .Close()
|
||||
}()
|
||||
// TODO(gri) The design draft doesn't require that we repeat
|
||||
// the type parameters here. Fix the implementation.
|
||||
_ = receiver
|
||||
panic(0)
|
||||
//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 /* ERROR not implemented */ .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)) 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
|
||||
}
|
||||
Loading…
Reference in New Issue