mirror of https://github.com/golang/go.git
go/*: fix parsing of T(P){...} comp. literals and add .go2 tests
Additionally, simplify the syntax for contracts specified in a
type parameter list: It is now not possible to provide explicit
type parameters to a contract in a type parameter list - they
are always implicit. For instance
func f(type P1, P2 C(P1, P2)) ...
must be written as
func f(type P1, P2 C) ...
If a different order or different types are desired for C,
a new "intermediate" contract must be declared, as in
contract C'(A, B) {
C(B, int) // here we allow type parameters
}
func f(type P1, P2 C')
This simplification will remove confusion if we decide to
allow individual contracts in type parameter lists, such as
func f(type P C, P1, P2 C') ...
In this case, C accepts one type parameter (and applies to P),
and C' accepts two type parameters and applies to P1 and P2.
The simplification avoids questions such as whether this code
should be permitted:
func f(type P C(P2), P1, P2 C'(P, P1)) ...
(i.e., can pass P2 to C, or P1 to C', etc.)
This commit is contained in:
parent
6069527287
commit
e3b54c8023
|
|
@ -1102,7 +1102,7 @@ func (p *parser) parseTypeParams(scope *ast.Scope) *ast.TypeParamList {
|
|||
}
|
||||
if p.tok == token.IDENT {
|
||||
// contract
|
||||
contract = p.parseType(true)
|
||||
contract = p.parseTypeName(nil)
|
||||
}
|
||||
|
||||
if lbrack.IsValid() {
|
||||
|
|
@ -1785,23 +1785,6 @@ func isTypeName(x ast.Expr) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// isLiteralType reports whether x is a legal composite literal type.
|
||||
func isLiteralType(x ast.Expr) bool {
|
||||
switch t := x.(type) {
|
||||
case *ast.BadExpr:
|
||||
case *ast.Ident:
|
||||
case *ast.SelectorExpr:
|
||||
_, isIdent := t.X.(*ast.Ident)
|
||||
return isIdent
|
||||
case *ast.ArrayType:
|
||||
case *ast.StructType:
|
||||
case *ast.MapType:
|
||||
default:
|
||||
return false // all other nodes are not legal composite literal types
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// If x is of the form *T, deref returns T, otherwise it returns x.
|
||||
func deref(x ast.Expr) ast.Expr {
|
||||
if p, isPtr := x.(*ast.StarExpr); isPtr {
|
||||
|
|
@ -1837,13 +1820,12 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
|
|||
}
|
||||
|
||||
// If lhs is set and the result is an identifier, it is not resolved.
|
||||
func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
|
||||
func (p *parser) parsePrimaryExpr(lhs bool) (x ast.Expr) {
|
||||
if p.trace {
|
||||
defer un(trace(p, "PrimaryExpr"))
|
||||
}
|
||||
|
||||
x := p.parseOperand(lhs)
|
||||
L:
|
||||
x = p.parseOperand(lhs)
|
||||
for {
|
||||
switch p.tok {
|
||||
case token.PERIOD:
|
||||
|
|
@ -1874,23 +1856,31 @@ L:
|
|||
}
|
||||
x = p.parseCallOrConversion(p.checkExprOrType(x))
|
||||
case token.LBRACE:
|
||||
// TODO(gri) currently this doesn't accept instantiated types
|
||||
// Use code from cmd/compile/internal/syntax/parser.go.
|
||||
if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
|
||||
if lhs {
|
||||
p.resolve(x)
|
||||
// operand may have returned a parenthesized complit
|
||||
// type; accept it but complain if we have a complit
|
||||
t := unparen(x)
|
||||
// determine if '{' belongs to a composite literal or a block statement
|
||||
switch t.(type) {
|
||||
case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr, *ast.CallExpr: // *ast.CallExpr for instantiated types
|
||||
if p.exprLev < 0 {
|
||||
return
|
||||
}
|
||||
x = p.parseLiteralValue(x)
|
||||
} else {
|
||||
break L
|
||||
// x is (possibly a) composite literal type
|
||||
case *ast.ArrayType, *ast.StructType, *ast.MapType:
|
||||
// x is a composite literal type
|
||||
default:
|
||||
return
|
||||
}
|
||||
if t != x {
|
||||
p.error(t.Pos(), "cannot parenthesize type in composite literal")
|
||||
// already progressed, no need to advance
|
||||
}
|
||||
x = p.parseLiteralValue(x)
|
||||
default:
|
||||
break L
|
||||
return
|
||||
}
|
||||
lhs = false // no need to try to resolve again
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
// If lhs is set and the result is an identifier, it is not resolved.
|
||||
|
|
@ -2215,7 +2205,7 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
|
|||
}
|
||||
// p.tok != token.LBRACE
|
||||
|
||||
outer := p.exprLev
|
||||
prevLev := p.exprLev
|
||||
p.exprLev = -1
|
||||
|
||||
if p.tok != token.SEMICOLON {
|
||||
|
|
@ -2263,7 +2253,7 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
|
|||
cond = &ast.BadExpr{From: p.pos, To: p.pos}
|
||||
}
|
||||
|
||||
p.exprLev = outer
|
||||
p.exprLev = prevLev
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ var valids = []string{
|
|||
`package p; type T (*int)`,
|
||||
`package p; type T(type P) struct { P }`,
|
||||
`package p; type T(type P comparable) struct { P }`,
|
||||
`package p; type T(type P comparable(P)) struct { P }`,
|
||||
// `package p; type T(type P comparable(P)) struct { P }`,
|
||||
`package p; type T(type P1, P2) struct { P1; f []P2 }`,
|
||||
// `package p; type T[type] struct { P }`,
|
||||
// `package p; type T[type P] struct { P }`,
|
||||
|
|
@ -68,7 +68,7 @@ var valids = []string{
|
|||
`package p; func _((T(P1, P2, P3)))`,
|
||||
`package p; func _(type A, B)(a A) B`,
|
||||
`package p; func _(type A, B C)(a A) B`,
|
||||
`package p; func _(type A, B C(A, B))(a A) B`,
|
||||
// `package p; func _(type A, B C(A, B))(a A) B`,
|
||||
// `package p; type _ struct { T[P] }`,
|
||||
// `package p; type _ struct { T []E }`,
|
||||
// `package p; type _ struct { T [P]E }`,
|
||||
|
|
@ -97,7 +97,7 @@ func TestValid(t *testing.T) {
|
|||
|
||||
// TestSingle is useful to track down a problem with a single short test program.
|
||||
func TestSingle(t *testing.T) {
|
||||
const src = `package p; func _((T(a, b,)))`
|
||||
const src = `package p; var _ = T(P){}`
|
||||
checkErrors(t, src, src)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -18,8 +18,7 @@ type node(type K, V) struct {
|
|||
|
||||
// New returns a new map.
|
||||
func New(type K, V)(compare func(K, K) int) *Map(K, V) {
|
||||
// TODO
|
||||
// return &Map(K, V){compare: compare}
|
||||
return &Map(K, V){compare: compare}
|
||||
}
|
||||
|
||||
// find looks up key in the map, and returns either a pointer
|
||||
|
|
@ -49,8 +48,7 @@ func (m *Map(K, V)) Insert(key K, val V) bool {
|
|||
(*pn).val = val
|
||||
return false
|
||||
}
|
||||
// TODO
|
||||
// *pn = &node(K, V){key: key, val: val}
|
||||
*pn = &node(K, V){key: key, val: val}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
package metrics
|
||||
|
||||
import "sync"
|
||||
|
||||
type Metric1(type T comparable) struct {
|
||||
mu sync.Mutex
|
||||
m map[T]int
|
||||
}
|
||||
|
||||
func (m *Metric1(T)) Add(v T) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if m.m == nil {
|
||||
m.m = make(map[T]int)
|
||||
}
|
||||
m[v]++
|
||||
}
|
||||
|
||||
contract cmp2(T1, T2) {
|
||||
comparable(T1)
|
||||
comparable(T2)
|
||||
}
|
||||
|
||||
type key2(type T1, T2 cmp2) struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
}
|
||||
|
||||
type Metric2(type T1, T2 cmp2) struct {
|
||||
mu sync.Mutex
|
||||
m map[key2(T1, T2)]int
|
||||
}
|
||||
|
||||
func (m *Metric2(T1, T2)) Add(v1 T1, v2 T2) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if m.m == nil {
|
||||
m.m = make(map[key2(T1, T2)]int)
|
||||
}
|
||||
m[key(T1, T2){v1, v2}]++
|
||||
}
|
||||
|
||||
contract cmp3(T1, T2, T3) {
|
||||
comparable(T1)
|
||||
comparable(T2)
|
||||
comparable(T3)
|
||||
}
|
||||
|
||||
type key3(type T1, T2, T3 cmp3) struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
f3 T3
|
||||
}
|
||||
|
||||
type Metric3(type T1, T2, T3 cmp3) struct {
|
||||
mu sync.Mutex
|
||||
m map[key3(T1, T2, T3)]int
|
||||
}
|
||||
|
||||
func (m *Metric3(T1, T2, T3)) Add(v1 T1, v2 T2, v3 T3) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if m.m == nil {
|
||||
m.m = make(map[key3]int)
|
||||
}
|
||||
m[key(T1, T2, T3){v1, v2, v3}]++
|
||||
}
|
||||
|
||||
// Repeat for the maximum number of permitted arguments.
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Package set implements sets of any type.
|
||||
package set
|
||||
|
||||
type Set(type Elem comparable) map[Elem]struct{}
|
||||
|
||||
func Make(type Elem comparable)() Set(Elem) {
|
||||
return make(Set(Elem))
|
||||
}
|
||||
|
||||
func (s Set(Elem)) Add(v Elem) {
|
||||
s[v] = struct{}{}
|
||||
}
|
||||
|
||||
func (s Set(Elem)) Delete(v Elem) {
|
||||
delete(s, v)
|
||||
}
|
||||
|
||||
func (s Set(Elem)) Contains(v Elem) bool {
|
||||
_, ok := s[v]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (s Set(Elem)) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s Set(Elem)) Iterate(f func(Elem)) {
|
||||
for v := range s {
|
||||
f(v)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Package slices implements various slice algorithms.
|
||||
package slices
|
||||
|
||||
// Map turns a []T1 to a []T2 using a mapping function.
|
||||
func Map(type T1, T2)(s []T1, f func(T1) T2) []T2 {
|
||||
r := make([]T2, len(s))
|
||||
for i, v := range s {
|
||||
r[i] = f(v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Reduce reduces a []T1 to a single value using a reduction function.
|
||||
func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 {
|
||||
r := initializer
|
||||
for _, v := range s {
|
||||
r = f(r, v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Filter filters values from a slice using a filter function.
|
||||
func Filter(type T)(s []T, f func(T) bool) []T {
|
||||
var r []T
|
||||
for _, v := range s {
|
||||
if f(v) {
|
||||
r = append(r, v)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package sort
|
||||
|
||||
type orderedSlice(type Elem comparable) []Elem
|
||||
|
||||
func (s orderedSlice(Elem)) Len() int { return len(s) }
|
||||
func (s orderedSlice(Elem)) Less(i, j int) bool { return s[i] < s[j] }
|
||||
func (s orderedSlice(Elem)) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// OrderedSlice sorts the slice s in ascending order.
|
||||
// The elements of s must be ordered using the < operator.
|
||||
func OrderedSlice(type Elem comparable)(s []Elem) {
|
||||
sort.Sort(orderedSlice(Elem)(s))
|
||||
}
|
||||
|
||||
type sliceFn(type Elem) struct {
|
||||
s []Elem
|
||||
f func(Elem, Elem) bool
|
||||
}
|
||||
|
||||
func (s sliceFn(Elem)) Len() int { return len(s.s) }
|
||||
func (s sliceFn(Elem)) Less(i, j int) bool { return s.f(s.s[i], s.s[j]) }
|
||||
func (s sliceFn(Elem)) Swap(i, j int) { s.s[i], s.s[j] = s.s[j], s.s[i] }
|
||||
|
||||
// SliceFn sorts the slice s according to the function f.
|
||||
func SliceFn(type Elem)(s []Elem, f func(Elem, Elem) bool) {
|
||||
Sort(sliceFn(Elem){s, f})
|
||||
}
|
||||
Loading…
Reference in New Issue