go/go2go, cmd/go2go, test: rewrite example code to not use contracts

Don't emit interfaces that are type bounds in the generated .go file.

Change-Id: I9b0fd2f6041e9464147ad6d82d349fe894ea762d
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go2-dev/+/735474
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Ian Lance Taylor 2020-05-02 16:00:47 -07:00 committed by Robert Griesemer
parent e83c4715b0
commit db04e7cb2e
10 changed files with 88 additions and 75 deletions

View File

@ -2,30 +2,30 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package contracts defines some useful contracts.
// Package contracts defines some useful type bounds.
package contracts
// The Ordered contract permits any ordered type: any type that supports
// Ordered permits any ordered type: any type that supports
// the operations <, <=, >=, >, as well as == and !=.
contract Ordered(T) {
T int, int8, int16, int32, int64,
type Ordered interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64,
string
}
// The Integer contract permits any integer type.
contract Integer(T) {
T int, int8, int16, int32, int64,
// Integer permits any integer type.
type Integer interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr
}
// The Signed contract permits any signed integer type.
contract Signed(T) {
T int, int8, int16, int32, int64
// Signed permits any signed integer type.
type Signed interface {
type int, int8, int16, int32, int64
}
// The Unsigned contract permits any unsigned integer type.
contract Unsigned(T) {
T uint, uint8, uint16, uint32, uint64, uintptr
// Unsigned permits any unsigned integer type.
type Unsigned interface {
type uint, uint8, uint16, uint32, uint64, uintptr
}

View File

@ -10,27 +10,31 @@ import "errors"
// A Graph is a collection of nodes. A node may have an arbitrary number
// of edges. An edge connects two nodes. Both nodes and edges must be
// comparable. This is an undirected simple graph.
type Graph(type Node, Edge G) struct {
type Graph(type Node NodeC(Edge), Edge EdgeC(Node)) struct {
nodes []Node
}
// G is the contract that the Graph Node and Edge types must implement.
contract G(Node, Edge) {
Node Edges() []Edge
comparable(Node)
Edge Nodes() (a, b Node)
comparable(Edge)
// NodeC is the contraints on a node in a graph, given the Edge type.
type NodeC(type Edge) interface {
comparable
Edges() []Edge
}
// Edgec is the constraints on an edge in a graph, given the Node type.
type EdgeC(type Node) interface {
comparable
Nodes() (a, b Node)
}
// New creates a new Graph from a collection of Nodes.
func New(type Node, Edge G)(nodes []Node) *Graph(Node, Edge) {
func New(type Node NodeC(Edge), Edge EdgeC(Node))(nodes []Node) *Graph(Node, Edge) {
return &Graph(Node, Edge){nodes: nodes}
}
// nodePath holds the path to a node during ShortestPath.
// This should ideally be a type defined inside ShortestPath,
// but the translator tool doesn't support that.
type nodePath(type Node, Edge G) struct {
type nodePath(type Node NodeC(Edge), Edge EdgeC(Node)) struct {
node Node
path []Edge
}
@ -67,28 +71,32 @@ func (g *Graph(Node, Edge)) ShortestPath(from, to Node) ([]Edge, error) {
return nil, errors.New("no path")
}
// GraphP is a version of Grgaph that uses pointers. This is for testing.
// GraphP is a version of Graph that uses pointers. This is for testing.
// I'm not sure which approach will be better in practice, or whether
// this indicates a problem with the draft design.
type GraphP(type Node, Edge GP) struct {
type GraphP(type Node NodeCP(Edge), Edge EdgeCP(Node)) struct {
nodes []*Node
}
// GP is the contract that the GraphP Node and Edge types must implement.
contract GP(Node, Edge) {
Node Edges() []*Edge
Edge Nodes() (a, b *Node)
// NodeCP is the contraint on a Node in a GraphP.
type NodeCP(type Edge) interface {
Edges() []*Edge
}
// EdgeCP is the contraint on an Edge in a GraphP.
type EdgeCP(type Node) interface {
Nodes() (a, b *Node)
}
// NewP creates a new GraphP from a collection of Nodes.
func NewP(type Node, Edge GP)(nodes []*Node) *GraphP(Node, Edge) {
func NewP(type Node NodeCP(Edge), Edge EdgeCP(Node))(nodes []*Node) *GraphP(Node, Edge) {
return &GraphP(Node, Edge){nodes: nodes}
}
// nodePathP holds the path to a node during ShortestPath.
// This should ideally be a type defined inside ShortestPath,
// but the translator tool doesn't support that.
type nodePathP(type Node, Edge GP) struct {
type nodePathP(type Node NodeCP(Edge), Edge EdgeCP(Node)) struct {
node *Node
path []*Edge
}

View File

@ -5,9 +5,12 @@
// Package maps implements simple functions to manipulate maps in various ways.
package maps
// any is a convenient type bound.
type any interface{}
// Keys returns the keys of the map m.
// The keys will be an indeterminate order.
func Keys(type K, V comparable(K))(m map[K]V) []K {
func Keys(type K comparable, V any)(m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
@ -17,7 +20,7 @@ func Keys(type K, V comparable(K))(m map[K]V) []K {
// Values returns the values of the map m.
// The values will be in an indeterminate order.
func Values(type K, V comparable(K))(m map[K]V) []V {
func Values(type K comparable, V any)(m map[K]V) []V {
r := make([]V, 0, len(m))
for _, v := range m {
r = append(r, v)
@ -25,14 +28,9 @@ func Values(type K, V comparable(K))(m map[K]V) []V {
return r
}
contract twocomparable(K, V) {
comparable(K)
comparable(V)
}
// Equal reports whether two maps contain the same key/value pairs.
// Values are compared using ==.
func Equal(type K, V twocomparable)(m1, m2 map[K]V) bool {
func Equal(type K, V comparable)(m1, m2 map[K]V) bool {
if len(m1) != len(m2) {
return false
}
@ -45,7 +43,7 @@ func Equal(type K, V twocomparable)(m1, m2 map[K]V) bool {
}
// Copy returns a copy of m.
func Copy(type K, V comparable(K))(m map[K]V) map[K]V {
func Copy(type K comparable, V any)(m map[K]V) map[K]V {
r := make(map[K]V, len(m))
for k, v := range m {
r[k] = v
@ -55,7 +53,7 @@ func Copy(type K, V comparable(K))(m map[K]V) map[K]V {
// Add adds all key/value pairs in m2 to m1. Keys in m2 that are already
// present in m1 will be overwritten with the value in m2.
func Add(type K, V comparable(K))(m1, m2 map[K]V) {
func Add(type K comparable, V any)(m1, m2 map[K]V) {
for k, v := range m2 {
m1[k] = v
}
@ -63,7 +61,7 @@ func Add(type K, V comparable(K))(m1, m2 map[K]V) {
// Sub removes all keys in m2 from m1. Keys in m2 that are not present
// in m1 are ignored. The values in m2 are ignored.
func Sub(type K, V comparable(K))(m1, m2 map[K]V) {
func Sub(type K comparable, V any)(m1, m2 map[K]V) {
for k := range m2 {
delete(m1, k)
}
@ -71,7 +69,7 @@ func Sub(type K, V comparable(K))(m1, m2 map[K]V) {
// Intersect removes all keys from m1 that are not present in m2.
// Keys in m2 that are not in m1 are ignored. The values in m2 are ignored.
func Intersect(type K, V comparable(K))(m1, m2 map[K]V) {
func Intersect(type K comparable, V any)(m1, m2 map[K]V) {
for k := range m1 {
if _, ok := m2[k]; !ok {
delete(m1, k)
@ -80,7 +78,7 @@ func Intersect(type K, V comparable(K))(m1, m2 map[K]V) {
}
// Filter deletes any key/value pairs from m for which f returns false.
func Filter(type K, V comparable(K))(m map[K]V, f func(K, V) bool) {
func Filter(type K comparable, V any)(m map[K]V, f func(K, V) bool) {
for k, v := range m {
if !f(k, v) {
delete(m, k)
@ -89,7 +87,7 @@ func Filter(type K, V comparable(K))(m map[K]V, f func(K, V) bool) {
}
// TransformValues applies f to each value in m. The keys remain unchanged.
func TransformValues(type K, V comparable(K))(m map[K]V, f func(V) V) {
func TransformValues(type K comparable, V any)(m map[K]V, f func(V) V) {
for k, v := range m {
m[k] = f(v)
}

View File

@ -38,18 +38,13 @@ func (m *Metric1(T)) Metrics() []T {
return maps.Keys(m.m)
}
contract cmp2(T1, T2) {
comparable(T1)
comparable(T2)
}
type key2(type T1, T2 cmp2) struct {
type key2(type T1, T2 comparable) struct {
f1 T1
f2 T2
}
// Metric2 tracks metrics of pairs of values.
type Metric2(type T1, T2 cmp2) struct {
type Metric2(type T1, T2 comparable) struct {
mu sync.Mutex
m map[key2(T1, T2)]int
}
@ -78,20 +73,14 @@ func (m *Metric2(T1, T2)) Metrics() (r1 []T1, r2 []T2) {
return r1, r2
}
contract cmp3(T1, T2, T3) {
comparable(T1)
comparable(T2)
comparable(T3)
}
type key3(type T1, T2, T3 cmp3) struct {
type key3(type T1, T2, T3 comparable) struct {
f1 T1
f2 T2
f3 T3
}
// Metric3 tracks metrics of triplets of values.
type Metric3(type T1, T2, T3 cmp3) struct {
type Metric3(type T1, T2, T3 comparable) struct {
mu sync.Mutex
m map[key3(T1, T2, T3)]int
}

View File

@ -37,7 +37,7 @@ func New(type K, V)(compare func(K, K) int) *Map(K, V) {
// NewOrdered returns a new map whose key is an ordered type.
// This is like New, but does not require providing a compare function.
// The map compare function uses the obvious key ordering.
func NewOrdered(type K, V contracts.Ordered(K))() *Map(K, V) {
func NewOrdered(type K contracts.Ordered, V interface{})() *Map(K, V) {
return New(K, V)(func(k1, k2 K) int {
switch {
case k1 < k2:

View File

@ -52,6 +52,24 @@ func isParameterizedTypeDecl(s ast.Spec) bool {
return ts.TParams != nil
}
// isTypeBound reports whether s is an interface type that must be a
// type bound.
func isTypeBound(s ast.Spec) bool {
ts := s.(*ast.TypeSpec)
it, ok := ts.Type.(*ast.InterfaceType)
if !ok {
return false
}
for _, m := range it.Methods.List {
for _, n := range m.Names {
if n.Name == "type" {
return true
}
}
}
return false
}
// A translator is used to translate a file from Go with contracts to Go 1.
type translator struct {
fset *token.FileSet
@ -306,7 +324,7 @@ func (t *translator) translate(file *ast.File) {
case token.TYPE:
newSpecs := make([]ast.Spec, 0, len(decl.Specs))
for j := range decl.Specs {
if !isParameterizedTypeDecl(decl.Specs[j]) {
if !isParameterizedTypeDecl(decl.Specs[j]) && !isTypeBound(decl.Specs[j]) {
t.translateTypeSpec(&decl.Specs[j])
newSpecs = append(newSpecs, decl.Specs[j])
}

View File

@ -35,7 +35,7 @@ import (
)
// If AcceptContracts is set, contracts are accepted.
const AcceptContracts = true
const AcceptContracts = false
// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a

View File

@ -9,8 +9,8 @@ package p
func F1(type T comparable)() {}
func F2() { F1([]int)() } // ERROR "\[\]int does not satisfy comparable$"
contract C(T) {
T M()
type C interface {
M()
}
func F3(type T C)() {}
@ -18,12 +18,12 @@ func F4() { F3(int)() } // ERROR "int does not satisfy C.*method M"
func F5(type T)() { F3(T)() } // ERROR "T does not satisfy C.*method M"
contract signed(T) {
T int, int8, int16, int32, int64
type signed interface {
type int, int8, int16, int32, int64
}
contract integer(T) {
T int, int8, int16, int32, int64,
type integer interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr
}
@ -38,9 +38,9 @@ type MyUint uint
func F10(a MyInt) bool { return F6(a) }
func F11(a MyUint) bool { return F6(a) } // ERROR "MyUint does not satisfy signed.*uint not found in"
contract C2(T) {
C(T)
signed(T)
type C2 interface {
C
signed
}
func F20(type T C2)(a T) bool {

View File

@ -4,6 +4,6 @@
package a
contract C(T) {
T M()
type C interface {
M()
}

View File

@ -13,8 +13,8 @@ import (
"sort"
)
contract Ordered(T) {
T int, int8, int16, int32, int64,
type Ordered interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64,
string