mirror of
https://github.com/golang/go
synced 2024-09-05 16:04:50 +00:00
[dev.typeparams] import go2go changes to parse type parameters
This CL imports changes on the go2go branch to support parsing type params, as well as the unsubmitted changes from CL 269300 to remove support for parenthesize type parameter syntax. Change-Id: I27ab942ce69eab62c2a1800f8f9661c4dcb233fe Reviewed-on: https://go-review.googlesource.com/c/go/+/270857 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org> Trust: Robert Griesemer <gri@golang.org> Trust: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
a324aebb7d
commit
b56762129e
|
@ -114,6 +114,7 @@ func expectedErrors(fset *token.FileSet, filename string, src []byte) map[token.
|
|||
// of found errors and reports discrepancies.
|
||||
//
|
||||
func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) {
|
||||
t.Helper()
|
||||
for _, error := range found {
|
||||
// error.Pos is a token.Position, but we want
|
||||
// a token.Pos so we can do a map lookup
|
||||
|
@ -149,7 +150,8 @@ func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]str
|
|||
}
|
||||
}
|
||||
|
||||
func checkErrors(t *testing.T, filename string, input interface{}) {
|
||||
func checkErrors(t *testing.T, filename string, input interface{}, mode Mode) {
|
||||
t.Helper()
|
||||
src, err := readSource(filename, input)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -157,7 +159,7 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
|
|||
}
|
||||
|
||||
fset := token.NewFileSet()
|
||||
_, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors)
|
||||
_, err = ParseFile(fset, filename, src, mode)
|
||||
found, ok := err.(scanner.ErrorList)
|
||||
if err != nil && !ok {
|
||||
t.Error(err)
|
||||
|
@ -180,8 +182,12 @@ func TestErrors(t *testing.T) {
|
|||
}
|
||||
for _, fi := range list {
|
||||
name := fi.Name()
|
||||
if !fi.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".src") {
|
||||
checkErrors(t, filepath.Join(testdata, name), nil)
|
||||
if !fi.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) {
|
||||
mode := DeclarationErrors | AllErrors
|
||||
if strings.HasSuffix(name, ".go2") {
|
||||
mode |= ParseTypeParams
|
||||
}
|
||||
checkErrors(t, filepath.Join(testdata, name), nil, mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ const (
|
|||
Trace // print a trace of parsed productions
|
||||
DeclarationErrors // report declaration errors
|
||||
SpuriousErrors // same as AllErrors, for backward-compatibility
|
||||
ParseTypeParams // Placeholder. Will control the parsing of type parameters.
|
||||
AllErrors = SpuriousErrors // report all errors (not just the first 10 on different lines)
|
||||
)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -48,14 +48,106 @@ var valids = []string{
|
|||
`package p; var _ = map[*P]int{&P{}:0, {}:1}`,
|
||||
`package p; type T = int`,
|
||||
`package p; type (T = p.T; _ = struct{}; x = *T)`,
|
||||
`package p; type T (*int)`,
|
||||
|
||||
// structs with parameterized embedded fields (for symmetry with interfaces)
|
||||
`package p; type _ struct{ ((int)) }`,
|
||||
`package p; type _ struct{ (*(int)) }`,
|
||||
`package p; type _ struct{ ([]byte) }`, // disallowed by type-checker
|
||||
|
||||
// type parameters
|
||||
`package p; type T[P any] struct { P }`,
|
||||
`package p; type T[P comparable] struct { P }`,
|
||||
`package p; type T[P comparable[P]] struct { P }`,
|
||||
`package p; type T[P1, P2 any] struct { P1; f []P2 }`,
|
||||
`package p; type _ []T[int]`,
|
||||
|
||||
`package p; var _ = func()T(nil)`,
|
||||
`package p; func _[T any]()`,
|
||||
`package p; func _[T any]()()`,
|
||||
`package p; func _(T (P))`,
|
||||
`package p; func _(T []E)`,
|
||||
`package p; func _(T [P]E)`,
|
||||
`package p; func _(x T[P1, P2, P3])`,
|
||||
`package p; func _(x p.T[Q])`,
|
||||
`package p; func _(p.T[Q])`,
|
||||
|
||||
`package p; var _ T[chan int]`,
|
||||
`package p; func f[A, B any](); func _() { _ = f[int, int] }`,
|
||||
|
||||
`package p; type _[A interface{},] struct{}`,
|
||||
`package p; type _[A interface{}] struct{}`,
|
||||
`package p; type _[A, B any,] struct{}`,
|
||||
`package p; type _[A, B any] struct{}`,
|
||||
`package p; type _[A any,] struct{}`,
|
||||
`package p; type _ [A+B]struct{}`, // this is an array!
|
||||
`package p; type _[A any]struct{}`,
|
||||
`package p; type _[A any] struct{ A }`, // this is not an array!
|
||||
|
||||
`package p; func _[T any]()`,
|
||||
`package p; func _[T any](x T)`,
|
||||
`package p; func _[T1, T2 any](x T)`,
|
||||
|
||||
`package p; func (R) _()`,
|
||||
`package p; func (R[P]) _[T any]()`,
|
||||
`package p; func (_ R[P]) _[T any](x T)`,
|
||||
`package p; func (_ R[P, Q]) _[T1, T2 any](x T)`,
|
||||
|
||||
`package p; var _ = []T[int]{}`,
|
||||
`package p; var _ = [10]T[int]{}`,
|
||||
`package p; var _ = func()T[int]{}`,
|
||||
`package p; var _ = map[T[int]]T[int]{}`,
|
||||
`package p; var _ = chan T[int](x)`,
|
||||
`package p; func _(T[P])`,
|
||||
`package p; func _(T[P1, P2, P3])`,
|
||||
`package p; func _(T[P]) T[P]`,
|
||||
`package p; func _(_ T[P], T P) T[P]`,
|
||||
|
||||
`package p; func _[A, B any](a A) B`,
|
||||
`package p; func _[A, B C](a A) B`,
|
||||
`package p; func _[A, B C[A, B]](a A) B`,
|
||||
|
||||
// method type parameters (if methodTypeParamsOk)
|
||||
`package p; func (T) _[A, B any](a A) B`,
|
||||
`package p; func (T) _[A, B C](a A) B`,
|
||||
`package p; func (T) _[A, B C[A, B]](a A) B`,
|
||||
|
||||
// method type parameters are not permitted in interfaces.
|
||||
`package p; type _[A, B any] interface { _(a A) B }`,
|
||||
`package p; type _[A, B C[A, B]] interface { _(a A) B }`,
|
||||
|
||||
// type bounds
|
||||
`package p; func _[T1, T2 interface{}](x T1) T2`,
|
||||
`package p; func _[T1 interface{ m() }, T2, T3 interface{}](x T1, y T3) T2`,
|
||||
|
||||
// struct embedding
|
||||
`package p; type _ struct{ T[P] }`,
|
||||
`package p; type _ struct{ T[struct{a, b, c int}] }`,
|
||||
`package p; type _ struct{ f [n]E }`,
|
||||
`package p; type _ struct{ f [a+b+c+d]E }`,
|
||||
|
||||
// interfaces with type lists
|
||||
`package p; type _ interface{type int}`,
|
||||
`package p; type _ interface{type int, float32; type bool; m(); type string;}`,
|
||||
|
||||
// interface embedding
|
||||
`package p; type I1 interface{}; type I2 interface{ I1 }`,
|
||||
`package p; type I1[T any] interface{}; type I2 interface{ I1[int] }`,
|
||||
`package p; type I1[T any] interface{}; type I2[T any] interface{ I1[T] }`,
|
||||
}
|
||||
|
||||
func TestValid(t *testing.T) {
|
||||
for _, src := range valids {
|
||||
checkErrors(t, src, src)
|
||||
checkErrors(t, src, src, DeclarationErrors|AllErrors)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSingle is useful to track down a problem with a single short test program.
|
||||
func TestSingle(t *testing.T) {
|
||||
const src = `package p; var _ = T[P]{}`
|
||||
checkErrors(t, src, src, DeclarationErrors|AllErrors)
|
||||
}
|
||||
|
||||
var invalids = []string{
|
||||
`foo /* ERROR "expected 'package'" */ !`,
|
||||
`package p; func f() { if { /* ERROR "missing condition" */ } };`,
|
||||
|
@ -79,7 +171,6 @@ var invalids = []string{
|
|||
`package p; var a = chan /* ERROR "expected expression" */ int;`,
|
||||
`package p; var a = []int{[ /* ERROR "expected expression" */ ]int};`,
|
||||
`package p; var a = ( /* ERROR "expected expression" */ []int);`,
|
||||
`package p; var a = a[[ /* ERROR "expected expression" */ ]int:[]int];`,
|
||||
`package p; var a = <- /* ERROR "expected expression" */ chan int;`,
|
||||
`package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
|
||||
`package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
|
||||
|
@ -102,7 +193,22 @@ var invalids = []string{
|
|||
`package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
|
||||
`package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
|
||||
`package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`,
|
||||
`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
|
||||
//`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
|
||||
|
||||
// type parameters
|
||||
`package p; var _ func[ /* ERROR "cannot have type parameters" */ T any](T)`,
|
||||
`package p; func _() (type /* ERROR "found 'type'" */ T)(T)`,
|
||||
`package p; func (type /* ERROR "found 'type'" */ T)(T) _()`,
|
||||
`package p; type _[A+B, /* ERROR "expected ']'" */ ] int`,
|
||||
`package p; type _[_ any] int; var _ = T[] /* ERROR "expected operand" */ {}`,
|
||||
`package p; type T[P any] = /* ERROR "cannot be alias" */ T0`,
|
||||
`package p; func _[]/* ERROR "empty type parameter list" */()`,
|
||||
|
||||
// errors that could be improved
|
||||
`package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`, // TODO: should this be on the ':'?
|
||||
`package p; type _[A/* ERROR "all type parameters must be named" */,] struct{ A }`, // TODO: a better location would be after the ']'
|
||||
`package p; func _[type /* ERROR "all type parameters must be named" */P, *Q interface{}]()`, // TODO: this is confusing.
|
||||
`package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected 'IDENT'" */I1) }`, // TODO: compiler error is 'syntax error: cannot parenthesize embedded type'
|
||||
|
||||
// issue 8656
|
||||
`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,
|
||||
|
@ -118,11 +224,11 @@ var invalids = []string{
|
|||
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ y float }{};`,
|
||||
|
||||
// issue 11611
|
||||
`package p; type _ struct { int, } /* ERROR "expected type, found '}'" */ ;`,
|
||||
`package p; type _ struct { int, } /* ERROR "expected 'IDENT', found '}'" */ ;`,
|
||||
`package p; type _ struct { int, float } /* ERROR "expected type, found '}'" */ ;`,
|
||||
`package p; type _ struct { ( /* ERROR "expected anonymous field" */ int) };`,
|
||||
`package p; func _()(x, y, z ... /* ERROR "expected '\)', found '...'" */ int){}`,
|
||||
`package p; func _()(... /* ERROR "expected type, found '...'" */ int){}`,
|
||||
//`package p; type _ struct { ( /* ERROR "cannot parenthesize embedded type" */ int) };`,
|
||||
//`package p; func _()(x, y, z ... /* ERROR "expected '\)', found '...'" */ int){}`,
|
||||
//`package p; func _()(... /* ERROR "expected type, found '...'" */ int){}`,
|
||||
|
||||
// issue 13475
|
||||
`package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`,
|
||||
|
@ -131,6 +237,6 @@ var invalids = []string{
|
|||
|
||||
func TestInvalid(t *testing.T) {
|
||||
for _, src := range invalids {
|
||||
checkErrors(t, src, src)
|
||||
checkErrors(t, src, src, DeclarationErrors|AllErrors)
|
||||
}
|
||||
}
|
||||
|
|
62
src/go/parser/testdata/chans.go2
vendored
Normal file
62
src/go/parser/testdata/chans.go2
vendored
Normal file
|
@ -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[T any]() (*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[T any] 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[T any] 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)
|
||||
}
|
83
src/go/parser/testdata/linalg.go2
vendored
Normal file
83
src/go/parser/testdata/linalg.go2
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package linalg
|
||||
|
||||
import "math"
|
||||
|
||||
// Numeric is type bound that matches any numeric type.
|
||||
// It would likely be in a constraints package in the standard library.
|
||||
type Numeric interface {
|
||||
type int, int8, int16, int32, int64,
|
||||
uint, uint8, uint16, uint32, uint64, uintptr,
|
||||
float32, float64,
|
||||
complex64, complex128
|
||||
}
|
||||
|
||||
func DotProduct[T Numeric](s1, s2 []T) T {
|
||||
if len(s1) != len(s2) {
|
||||
panic("DotProduct: slices of unequal length")
|
||||
}
|
||||
var r T
|
||||
for i := range s1 {
|
||||
r += s1[i] * s2[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// NumericAbs matches numeric types with an Abs method.
|
||||
type NumericAbs[T any] interface {
|
||||
Numeric
|
||||
|
||||
Abs() T
|
||||
}
|
||||
|
||||
// AbsDifference computes the absolute value of the difference of
|
||||
// a and b, where the absolute value is determined by the Abs method.
|
||||
func AbsDifference[T NumericAbs](a, b T) T {
|
||||
d := a - b
|
||||
return d.Abs()
|
||||
}
|
||||
|
||||
// OrderedNumeric is a type bound that matches numeric types that support the < operator.
|
||||
type OrderedNumeric interface {
|
||||
type int, int8, int16, int32, int64,
|
||||
uint, uint8, uint16, uint32, uint64, uintptr,
|
||||
float32, float64
|
||||
}
|
||||
|
||||
// Complex is a type bound that matches the two complex types, which do not have a < operator.
|
||||
type Complex interface {
|
||||
type complex64, complex128
|
||||
}
|
||||
|
||||
// OrderedAbs is a helper type that defines an Abs method for
|
||||
// ordered numeric types.
|
||||
type OrderedAbs[T OrderedNumeric] T
|
||||
|
||||
func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
|
||||
if a < 0 {
|
||||
return -a
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ComplexAbs is a helper type that defines an Abs method for
|
||||
// complex types.
|
||||
type ComplexAbs[T Complex] T
|
||||
|
||||
func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
|
||||
r := float64(real(a))
|
||||
i := float64(imag(a))
|
||||
d := math.Sqrt(r * r + i * i)
|
||||
return ComplexAbs[T](complex(d, 0))
|
||||
}
|
||||
|
||||
func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
|
||||
return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
|
||||
}
|
||||
|
||||
func ComplexAbsDifference[T Complex](a, b T) T {
|
||||
return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
|
||||
}
|
109
src/go/parser/testdata/map.go2
vendored
Normal file
109
src/go/parser/testdata/map.go2
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Package orderedmap provides an ordered map, implemented as a binary tree.
|
||||
package orderedmap
|
||||
|
||||
import "chans"
|
||||
|
||||
// Map is an ordered map.
|
||||
type Map[K, V any] struct {
|
||||
root *node[K, V]
|
||||
compare func(K, K) int
|
||||
}
|
||||
|
||||
// node is the type of a node in the binary tree.
|
||||
type node[K, V any] struct {
|
||||
key K
|
||||
val V
|
||||
left, right *node[K, V]
|
||||
}
|
||||
|
||||
// New returns a new map.
|
||||
func New[K, V any](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.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.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[K, V any] 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.Close()
|
||||
}()
|
||||
return &Iterator{receiver}
|
||||
}
|
||||
|
||||
// Iterator is used to iterate over the map.
|
||||
type Iterator[K, V any] 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.r.Next()
|
||||
if !ok {
|
||||
var zerok K
|
||||
var zerov V
|
||||
return zerok, zerov, false
|
||||
}
|
||||
return keyval.key, keyval.val, true
|
||||
}
|
58
src/go/parser/testdata/metrics.go2
vendored
Normal file
58
src/go/parser/testdata/metrics.go2
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
package metrics
|
||||
|
||||
import "sync"
|
||||
|
||||
type Metric1[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]++
|
||||
}
|
||||
|
||||
type key2[T1, T2 comparable] struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
}
|
||||
|
||||
type Metric2[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}]++
|
||||
}
|
||||
|
||||
type key3[T1, T2, T3 comparable] struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
f3 T3
|
||||
}
|
||||
|
||||
type Metric3[T1, T2, T3 comparable] 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.
|
31
src/go/parser/testdata/set.go2
vendored
Normal file
31
src/go/parser/testdata/set.go2
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Package set implements sets of any type.
|
||||
package set
|
||||
|
||||
type Set[Elem comparable] map[Elem]struct{}
|
||||
|
||||
func Make[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)
|
||||
}
|
||||
}
|
31
src/go/parser/testdata/slices.go2
vendored
Normal file
31
src/go/parser/testdata/slices.go2
vendored
Normal file
|
@ -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[T1, T2 any](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[T1, T2 any](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[T any](s []T, f func(T) bool) []T {
|
||||
var r []T
|
||||
for _, v := range s {
|
||||
if f(v) {
|
||||
r = append(r, v)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
27
src/go/parser/testdata/sort.go2
vendored
Normal file
27
src/go/parser/testdata/sort.go2
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
package sort
|
||||
|
||||
type orderedSlice[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[Elem comparable](s []Elem) {
|
||||
sort.Sort(orderedSlice[Elem](s))
|
||||
}
|
||||
|
||||
type sliceFn[Elem any] 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[Elem any](s []Elem, f func(Elem, Elem) bool) {
|
||||
Sort(sliceFn[Elem]{s, f})
|
||||
}
|
4
src/go/types/testdata/issues.src
vendored
4
src/go/types/testdata/issues.src
vendored
|
@ -325,8 +325,8 @@ func issue28281c(a, b, c ... /* ERROR can only use ... with final parameter */ i
|
|||
func issue28281d(... /* ERROR can only use ... with final parameter */ int, int)
|
||||
func issue28281e(a, b, c ... /* ERROR can only use ... with final parameter */ int, d int)
|
||||
func issue28281f(... /* ERROR can only use ... with final parameter */ int, ... /* ERROR can only use ... with final parameter */ int, int)
|
||||
func (... /* ERROR expected type */ TT) f()
|
||||
func issue28281g() (... /* ERROR expected type */ TT)
|
||||
func (... /* ERROR can only use ... with final parameter */ TT) f()
|
||||
func issue28281g() (... /* ERROR can only use ... with final parameter */ TT)
|
||||
|
||||
// Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output
|
||||
func issue26234a(f *syn.File) {
|
||||
|
|
Loading…
Reference in a new issue