mirror of https://github.com/golang/go.git
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:
parent
e83c4715b0
commit
db04e7cb2e
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
package a
|
||||
|
||||
contract C(T) {
|
||||
T M()
|
||||
type C interface {
|
||||
M()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue