go/types: add testdata/map2.go2, update README

Change-Id: I5a859fe3298998810ba56f3b445fae8e1d177995
This commit is contained in:
Robert Griesemer 2019-08-16 16:52:15 -07:00
parent 5891f8c720
commit 0ac0b8518c
3 changed files with 152 additions and 17 deletions

View File

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

View File

@ -110,6 +110,7 @@ var tests = [][]string{
{"testdata/slices.go2"},
{"testdata/chans.go2"},
{"testdata/map.go2"},
{"testdata/map2.go2"},
}
var fset = token.NewFileSet()

139
src/go/types/testdata/map2.go2 vendored Normal file
View File

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