diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index ab6175047a..45d5b8851c 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -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 } diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index fe83adae13..bf7fcc59ba 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -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) } diff --git a/src/go/parser/testdata/chans.go2 b/src/go/parser/testdata/chans.go2 new file mode 100644 index 0000000000..d6ca4df447 --- /dev/null +++ b/src/go/parser/testdata/chans.go2 @@ -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) +} diff --git a/src/go/parser/testdata/map.go2 b/src/go/parser/testdata/map.go2 index 036663c1c7..8b0cdaaa67 100644 --- a/src/go/parser/testdata/map.go2 +++ b/src/go/parser/testdata/map.go2 @@ -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 } diff --git a/src/go/parser/testdata/metrics.go2 b/src/go/parser/testdata/metrics.go2 new file mode 100644 index 0000000000..a435442d0b --- /dev/null +++ b/src/go/parser/testdata/metrics.go2 @@ -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. diff --git a/src/go/parser/testdata/set.go2 b/src/go/parser/testdata/set.go2 new file mode 100644 index 0000000000..bc18550a06 --- /dev/null +++ b/src/go/parser/testdata/set.go2 @@ -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) + } +} diff --git a/src/go/parser/testdata/slices.go2 b/src/go/parser/testdata/slices.go2 new file mode 100644 index 0000000000..fe90f7cfe9 --- /dev/null +++ b/src/go/parser/testdata/slices.go2 @@ -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 +} diff --git a/src/go/parser/testdata/sort.go2 b/src/go/parser/testdata/sort.go2 new file mode 100644 index 0000000000..241b8fb348 --- /dev/null +++ b/src/go/parser/testdata/sort.go2 @@ -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}) +}