diff options
Diffstat (limited to 'libgo/go/golang.org/x')
89 files changed, 4984 insertions, 572 deletions
diff --git a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go index 0d7bac3f7db..93da7322bc4 100644 --- a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go +++ b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go @@ -26,6 +26,10 @@ const ( // NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305 // variant of this AEAD, in bytes. NonceSizeX = 24 + + // Overhead is the size of the Poly1305 authentication tag, and the + // difference between a ciphertext length and its plaintext. + Overhead = 16 ) type chacha20poly1305 struct { @@ -47,7 +51,7 @@ func (c *chacha20poly1305) NonceSize() int { } func (c *chacha20poly1305) Overhead() int { - return 16 + return Overhead } func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { diff --git a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go index fe191d395d5..96b2fd898bb 100644 --- a/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go +++ b/libgo/go/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go @@ -8,8 +8,8 @@ import ( "encoding/binary" "golang.org/x/crypto/chacha20" + "golang.org/x/crypto/internal/poly1305" "golang.org/x/crypto/internal/subtle" - "golang.org/x/crypto/poly1305" ) func writeWithPadding(p *poly1305.MAC, b []byte) { diff --git a/libgo/go/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go b/libgo/go/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go index d9d46b96396..1cebfe946f4 100644 --- a/libgo/go/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go +++ b/libgo/go/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go @@ -35,7 +35,7 @@ func (*xchacha20poly1305) NonceSize() int { } func (*xchacha20poly1305) Overhead() int { - return 16 + return Overhead } func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { diff --git a/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go b/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go index 83c776de083..3a1674a1e57 100644 --- a/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go +++ b/libgo/go/golang.org/x/crypto/cryptobyte/asn1.go @@ -407,7 +407,12 @@ func (s *String) ReadASN1Enum(out *int) bool { func (s *String) readBase128Int(out *int) bool { ret := 0 for i := 0; len(*s) > 0; i++ { - if i == 4 { + if i == 5 { + return false + } + // Avoid overflowing int on a 32-bit platform. + // We don't want different behavior based on the architecture. + if ret >= 1<<(31-7) { return false } ret <<= 7 diff --git a/libgo/go/golang.org/x/crypto/curve25519/curve25519.go b/libgo/go/golang.org/x/crypto/curve25519/curve25519.go index 4b9a655d1b5..cda3fdd3540 100644 --- a/libgo/go/golang.org/x/crypto/curve25519/curve25519.go +++ b/libgo/go/golang.org/x/crypto/curve25519/curve25519.go @@ -10,6 +10,8 @@ package curve25519 // import "golang.org/x/crypto/curve25519" import ( "crypto/subtle" "fmt" + + "golang.org/x/crypto/curve25519/internal/field" ) // ScalarMult sets dst to the product scalar * point. @@ -18,7 +20,55 @@ import ( // zeroes, irrespective of the scalar. Instead, use the X25519 function, which // will return an error. func ScalarMult(dst, scalar, point *[32]byte) { - scalarMult(dst, scalar, point) + var e [32]byte + + copy(e[:], scalar[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element + x1.SetBytes(point[:]) + x2.One() + x3.Set(&x1) + z3.One() + + swap := 0 + for pos := 254; pos >= 0; pos-- { + b := e[pos/8] >> uint(pos&7) + b &= 1 + swap ^= int(b) + x2.Swap(&x3, swap) + z2.Swap(&z3, swap) + swap = int(b) + + tmp0.Subtract(&x3, &z3) + tmp1.Subtract(&x2, &z2) + x2.Add(&x2, &z2) + z2.Add(&x3, &z3) + z3.Multiply(&tmp0, &x2) + z2.Multiply(&z2, &tmp1) + tmp0.Square(&tmp1) + tmp1.Square(&x2) + x3.Add(&z3, &z2) + z2.Subtract(&z3, &z2) + x2.Multiply(&tmp1, &tmp0) + tmp1.Subtract(&tmp1, &tmp0) + z2.Square(&z2) + + z3.Mult32(&tmp1, 121666) + x3.Square(&x3) + tmp0.Add(&tmp0, &z3) + z3.Multiply(&x1, &z2) + z2.Multiply(&tmp1, &tmp0) + } + + x2.Swap(&x3, swap) + z2.Swap(&z3, swap) + + z2.Invert(&z2) + x2.Multiply(&x2, &z2) + copy(dst[:], x2.Bytes()) } // ScalarBaseMult sets dst to the product scalar * base where base is the diff --git a/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe.go b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe.go new file mode 100644 index 00000000000..ca841ad99e3 --- /dev/null +++ b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe.go @@ -0,0 +1,416 @@ +// Copyright (c) 2017 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 field implements fast arithmetic modulo 2^255-19. +package field + +import ( + "crypto/subtle" + "encoding/binary" + "math/bits" +) + +// Element represents an element of the field GF(2^255-19). Note that this +// is not a cryptographically secure group, and should only be used to interact +// with edwards25519.Point coordinates. +// +// This type works similarly to math/big.Int, and all arguments and receivers +// are allowed to alias. +// +// The zero value is a valid zero element. +type Element struct { + // An element t represents the integer + // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204 + // + // Between operations, all limbs are expected to be lower than 2^52. + l0 uint64 + l1 uint64 + l2 uint64 + l3 uint64 + l4 uint64 +} + +const maskLow51Bits uint64 = (1 << 51) - 1 + +var feZero = &Element{0, 0, 0, 0, 0} + +// Zero sets v = 0, and returns v. +func (v *Element) Zero() *Element { + *v = *feZero + return v +} + +var feOne = &Element{1, 0, 0, 0, 0} + +// One sets v = 1, and returns v. +func (v *Element) One() *Element { + *v = *feOne + return v +} + +// reduce reduces v modulo 2^255 - 19 and returns it. +func (v *Element) reduce() *Element { + v.carryPropagate() + + // After the light reduction we now have a field element representation + // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19. + + // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1, + // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise. + c := (v.l0 + 19) >> 51 + c = (v.l1 + c) >> 51 + c = (v.l2 + c) >> 51 + c = (v.l3 + c) >> 51 + c = (v.l4 + c) >> 51 + + // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's + // effectively applying the reduction identity to the carry. + v.l0 += 19 * c + + v.l1 += v.l0 >> 51 + v.l0 = v.l0 & maskLow51Bits + v.l2 += v.l1 >> 51 + v.l1 = v.l1 & maskLow51Bits + v.l3 += v.l2 >> 51 + v.l2 = v.l2 & maskLow51Bits + v.l4 += v.l3 >> 51 + v.l3 = v.l3 & maskLow51Bits + // no additional carry + v.l4 = v.l4 & maskLow51Bits + + return v +} + +// Add sets v = a + b, and returns v. +func (v *Element) Add(a, b *Element) *Element { + v.l0 = a.l0 + b.l0 + v.l1 = a.l1 + b.l1 + v.l2 = a.l2 + b.l2 + v.l3 = a.l3 + b.l3 + v.l4 = a.l4 + b.l4 + // Using the generic implementation here is actually faster than the + // assembly. Probably because the body of this function is so simple that + // the compiler can figure out better optimizations by inlining the carry + // propagation. TODO + return v.carryPropagateGeneric() +} + +// Subtract sets v = a - b, and returns v. +func (v *Element) Subtract(a, b *Element) *Element { + // We first add 2 * p, to guarantee the subtraction won't underflow, and + // then subtract b (which can be up to 2^255 + 2^13 * 19). + v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0 + v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1 + v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2 + v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3 + v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4 + return v.carryPropagate() +} + +// Negate sets v = -a, and returns v. +func (v *Element) Negate(a *Element) *Element { + return v.Subtract(feZero, a) +} + +// Invert sets v = 1/z mod p, and returns v. +// +// If z == 0, Invert returns v = 0. +func (v *Element) Invert(z *Element) *Element { + // Inversion is implemented as exponentiation with exponent p β 2. It uses the + // same sequence of 255 squarings and 11 multiplications as [Curve25519]. + var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element + + z2.Square(z) // 2 + t.Square(&z2) // 4 + t.Square(&t) // 8 + z9.Multiply(&t, z) // 9 + z11.Multiply(&z9, &z2) // 11 + t.Square(&z11) // 22 + z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0 + + t.Square(&z2_5_0) // 2^6 - 2^1 + for i := 0; i < 4; i++ { + t.Square(&t) // 2^10 - 2^5 + } + z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0 + + t.Square(&z2_10_0) // 2^11 - 2^1 + for i := 0; i < 9; i++ { + t.Square(&t) // 2^20 - 2^10 + } + z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0 + + t.Square(&z2_20_0) // 2^21 - 2^1 + for i := 0; i < 19; i++ { + t.Square(&t) // 2^40 - 2^20 + } + t.Multiply(&t, &z2_20_0) // 2^40 - 2^0 + + t.Square(&t) // 2^41 - 2^1 + for i := 0; i < 9; i++ { + t.Square(&t) // 2^50 - 2^10 + } + z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0 + + t.Square(&z2_50_0) // 2^51 - 2^1 + for i := 0; i < 49; i++ { + t.Square(&t) // 2^100 - 2^50 + } + z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0 + + t.Square(&z2_100_0) // 2^101 - 2^1 + for i := 0; i < 99; i++ { + t.Square(&t) // 2^200 - 2^100 + } + t.Multiply(&t, &z2_100_0) // 2^200 - 2^0 + + t.Square(&t) // 2^201 - 2^1 + for i := 0; i < 49; i++ { + t.Square(&t) // 2^250 - 2^50 + } + t.Multiply(&t, &z2_50_0) // 2^250 - 2^0 + + t.Square(&t) // 2^251 - 2^1 + t.Square(&t) // 2^252 - 2^2 + t.Square(&t) // 2^253 - 2^3 + t.Square(&t) // 2^254 - 2^4 + t.Square(&t) // 2^255 - 2^5 + + return v.Multiply(&t, &z11) // 2^255 - 21 +} + +// Set sets v = a, and returns v. +func (v *Element) Set(a *Element) *Element { + *v = *a + return v +} + +// SetBytes sets v to x, which must be a 32-byte little-endian encoding. +// +// Consistent with RFC 7748, the most significant bit (the high bit of the +// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1) +// are accepted. Note that this is laxer than specified by RFC 8032. +func (v *Element) SetBytes(x []byte) *Element { + if len(x) != 32 { + panic("edwards25519: invalid field element input size") + } + + // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). + v.l0 = binary.LittleEndian.Uint64(x[0:8]) + v.l0 &= maskLow51Bits + // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). + v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 + v.l1 &= maskLow51Bits + // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). + v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 + v.l2 &= maskLow51Bits + // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). + v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 + v.l3 &= maskLow51Bits + // Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51). + // Note: not bytes 25:33, shift 4, to avoid overread. + v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 + v.l4 &= maskLow51Bits + + return v +} + +// Bytes returns the canonical 32-byte little-endian encoding of v. +func (v *Element) Bytes() []byte { + // This function is outlined to make the allocations inline in the caller + // rather than happen on the heap. + var out [32]byte + return v.bytes(&out) +} + +func (v *Element) bytes(out *[32]byte) []byte { + t := *v + t.reduce() + + var buf [8]byte + for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { + bitsOffset := i * 51 + binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8)) + for i, bb := range buf { + off := bitsOffset/8 + i + if off >= len(out) { + break + } + out[off] |= bb + } + } + + return out[:] +} + +// Equal returns 1 if v and u are equal, and 0 otherwise. +func (v *Element) Equal(u *Element) int { + sa, sv := u.Bytes(), v.Bytes() + return subtle.ConstantTimeCompare(sa, sv) +} + +// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise. +func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) } + +// Select sets v to a if cond == 1, and to b if cond == 0. +func (v *Element) Select(a, b *Element, cond int) *Element { + m := mask64Bits(cond) + v.l0 = (m & a.l0) | (^m & b.l0) + v.l1 = (m & a.l1) | (^m & b.l1) + v.l2 = (m & a.l2) | (^m & b.l2) + v.l3 = (m & a.l3) | (^m & b.l3) + v.l4 = (m & a.l4) | (^m & b.l4) + return v +} + +// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v. +func (v *Element) Swap(u *Element, cond int) { + m := mask64Bits(cond) + t := m & (v.l0 ^ u.l0) + v.l0 ^= t + u.l0 ^= t + t = m & (v.l1 ^ u.l1) + v.l1 ^= t + u.l1 ^= t + t = m & (v.l2 ^ u.l2) + v.l2 ^= t + u.l2 ^= t + t = m & (v.l3 ^ u.l3) + v.l3 ^= t + u.l3 ^= t + t = m & (v.l4 ^ u.l4) + v.l4 ^= t + u.l4 ^= t +} + +// IsNegative returns 1 if v is negative, and 0 otherwise. +func (v *Element) IsNegative() int { + return int(v.Bytes()[0] & 1) +} + +// Absolute sets v to |u|, and returns v. +func (v *Element) Absolute(u *Element) *Element { + return v.Select(new(Element).Negate(u), u, u.IsNegative()) +} + +// Multiply sets v = x * y, and returns v. +func (v *Element) Multiply(x, y *Element) *Element { + feMul(v, x, y) + return v +} + +// Square sets v = x * x, and returns v. +func (v *Element) Square(x *Element) *Element { + feSquare(v, x) + return v +} + +// Mult32 sets v = x * y, and returns v. +func (v *Element) Mult32(x *Element, y uint32) *Element { + x0lo, x0hi := mul51(x.l0, y) + x1lo, x1hi := mul51(x.l1, y) + x2lo, x2hi := mul51(x.l2, y) + x3lo, x3hi := mul51(x.l3, y) + x4lo, x4hi := mul51(x.l4, y) + v.l0 = x0lo + 19*x4hi // carried over per the reduction identity + v.l1 = x1lo + x0hi + v.l2 = x2lo + x1hi + v.l3 = x3lo + x2hi + v.l4 = x4lo + x3hi + // The hi portions are going to be only 32 bits, plus any previous excess, + // so we can skip the carry propagation. + return v +} + +// mul51 returns lo + hi * 2β΅ΒΉ = a * b. +func mul51(a uint64, b uint32) (lo uint64, hi uint64) { + mh, ml := bits.Mul64(a, uint64(b)) + lo = ml & maskLow51Bits + hi = (mh << 13) | (ml >> 51) + return +} + +// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3. +func (v *Element) Pow22523(x *Element) *Element { + var t0, t1, t2 Element + + t0.Square(x) // x^2 + t1.Square(&t0) // x^4 + t1.Square(&t1) // x^8 + t1.Multiply(x, &t1) // x^9 + t0.Multiply(&t0, &t1) // x^11 + t0.Square(&t0) // x^22 + t0.Multiply(&t1, &t0) // x^31 + t1.Square(&t0) // x^62 + for i := 1; i < 5; i++ { // x^992 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1 + t1.Square(&t0) // 2^11 - 2 + for i := 1; i < 10; i++ { // 2^20 - 2^10 + t1.Square(&t1) + } + t1.Multiply(&t1, &t0) // 2^20 - 1 + t2.Square(&t1) // 2^21 - 2 + for i := 1; i < 20; i++ { // 2^40 - 2^20 + t2.Square(&t2) + } + t1.Multiply(&t2, &t1) // 2^40 - 1 + t1.Square(&t1) // 2^41 - 2 + for i := 1; i < 10; i++ { // 2^50 - 2^10 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // 2^50 - 1 + t1.Square(&t0) // 2^51 - 2 + for i := 1; i < 50; i++ { // 2^100 - 2^50 + t1.Square(&t1) + } + t1.Multiply(&t1, &t0) // 2^100 - 1 + t2.Square(&t1) // 2^101 - 2 + for i := 1; i < 100; i++ { // 2^200 - 2^100 + t2.Square(&t2) + } + t1.Multiply(&t2, &t1) // 2^200 - 1 + t1.Square(&t1) // 2^201 - 2 + for i := 1; i < 50; i++ { // 2^250 - 2^50 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // 2^250 - 1 + t0.Square(&t0) // 2^251 - 2 + t0.Square(&t0) // 2^252 - 4 + return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3) +} + +// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion. +var sqrtM1 = &Element{1718705420411056, 234908883556509, + 2233514472574048, 2117202627021982, 765476049583133} + +// SqrtRatio sets r to the non-negative square root of the ratio of u and v. +// +// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio +// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00, +// and returns r and 0. +func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) { + var a, b Element + + // r = (u * v3) * (u * v7)^((p-5)/8) + v2 := a.Square(v) + uv3 := b.Multiply(u, b.Multiply(v2, v)) + uv7 := a.Multiply(uv3, a.Square(v2)) + r.Multiply(uv3, r.Pow22523(uv7)) + + check := a.Multiply(v, a.Square(r)) // check = v * r^2 + + uNeg := b.Negate(u) + correctSignSqrt := check.Equal(u) + flippedSignSqrt := check.Equal(uNeg) + flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1)) + + rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r + // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r) + r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI) + + r.Absolute(r) // Choose the nonnegative square root. + return r, correctSignSqrt | flippedSignSqrt +} diff --git a/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go new file mode 100644 index 00000000000..8fe583939f1 --- /dev/null +++ b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go @@ -0,0 +1,14 @@ +// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. + +//go:build amd64 && gc && !purego +// +build amd64,gc,!purego + +package field + +// feMul sets out = a * b. It works like feMulGeneric. +//go:noescape +func feMul(out *Element, a *Element, b *Element) + +// feSquare sets out = a * a. It works like feSquareGeneric. +//go:noescape +func feSquare(out *Element, a *Element) diff --git a/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go new file mode 100644 index 00000000000..ddb6c9b8f7f --- /dev/null +++ b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go @@ -0,0 +1,12 @@ +// Copyright (c) 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. + +//go:build !amd64 || !gc || purego +// +build !amd64 !gc purego + +package field + +func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } + +func feSquare(v, x *Element) { feSquareGeneric(v, x) } diff --git a/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go new file mode 100644 index 00000000000..af459ef5154 --- /dev/null +++ b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go @@ -0,0 +1,16 @@ +// Copyright (c) 2020 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. + +//go:build arm64 && gc && !purego +// +build arm64,gc,!purego + +package field + +//go:noescape +func carryPropagate(v *Element) + +func (v *Element) carryPropagate() *Element { + carryPropagate(v) + return v +} diff --git a/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go new file mode 100644 index 00000000000..234a5b2e5d1 --- /dev/null +++ b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go @@ -0,0 +1,12 @@ +// Copyright (c) 2021 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. + +//go:build !arm64 || !gc || purego +// +build !arm64 !gc purego + +package field + +func (v *Element) carryPropagate() *Element { + return v.carryPropagateGeneric() +} diff --git a/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_generic.go b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_generic.go new file mode 100644 index 00000000000..7b5b78cbd6d --- /dev/null +++ b/libgo/go/golang.org/x/crypto/curve25519/internal/field/fe_generic.go @@ -0,0 +1,264 @@ +// Copyright (c) 2017 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 field + +import "math/bits" + +// uint128 holds a 128-bit number as two 64-bit limbs, for use with the +// bits.Mul64 and bits.Add64 intrinsics. +type uint128 struct { + lo, hi uint64 +} + +// mul64 returns a * b. +func mul64(a, b uint64) uint128 { + hi, lo := bits.Mul64(a, b) + return uint128{lo, hi} +} + +// addMul64 returns v + a * b. +func addMul64(v uint128, a, b uint64) uint128 { + hi, lo := bits.Mul64(a, b) + lo, c := bits.Add64(lo, v.lo, 0) + hi, _ = bits.Add64(hi, v.hi, c) + return uint128{lo, hi} +} + +// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits. +func shiftRightBy51(a uint128) uint64 { + return (a.hi << (64 - 51)) | (a.lo >> 51) +} + +func feMulGeneric(v, a, b *Element) { + a0 := a.l0 + a1 := a.l1 + a2 := a.l2 + a3 := a.l3 + a4 := a.l4 + + b0 := b.l0 + b1 := b.l1 + b2 := b.l2 + b3 := b.l3 + b4 := b.l4 + + // Limb multiplication works like pen-and-paper columnar multiplication, but + // with 51-bit limbs instead of digits. + // + // a4 a3 a2 a1 a0 x + // b4 b3 b2 b1 b0 = + // ------------------------ + // a4b0 a3b0 a2b0 a1b0 a0b0 + + // a4b1 a3b1 a2b1 a1b1 a0b1 + + // a4b2 a3b2 a2b2 a1b2 a0b2 + + // a4b3 a3b3 a2b3 a1b3 a0b3 + + // a4b4 a3b4 a2b4 a1b4 a0b4 = + // ---------------------------------------------- + // r8 r7 r6 r5 r4 r3 r2 r1 r0 + // + // We can then use the reduction identity (a * 2Β²β΅β΅ + b = a * 19 + b) to + // reduce the limbs that would overflow 255 bits. r5 * 2Β²β΅β΅ becomes 19 * r5, + // r6 * 2Β³β°βΆ becomes 19 * r6 * 2β΅ΒΉ, etc. + // + // Reduction can be carried out simultaneously to multiplication. For + // example, we do not compute r5: whenever the result of a multiplication + // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0. + // + // a4b0 a3b0 a2b0 a1b0 a0b0 + + // a3b1 a2b1 a1b1 a0b1 19Γa4b1 + + // a2b2 a1b2 a0b2 19Γa4b2 19Γa3b2 + + // a1b3 a0b3 19Γa4b3 19Γa3b3 19Γa2b3 + + // a0b4 19Γa4b4 19Γa3b4 19Γa2b4 19Γa1b4 = + // -------------------------------------- + // r4 r3 r2 r1 r0 + // + // Finally we add up the columns into wide, overlapping limbs. + + a1_19 := a1 * 19 + a2_19 := a2 * 19 + a3_19 := a3 * 19 + a4_19 := a4 * 19 + + // r0 = a0Γb0 + 19Γ(a1Γb4 + a2Γb3 + a3Γb2 + a4Γb1) + r0 := mul64(a0, b0) + r0 = addMul64(r0, a1_19, b4) + r0 = addMul64(r0, a2_19, b3) + r0 = addMul64(r0, a3_19, b2) + r0 = addMul64(r0, a4_19, b1) + + // r1 = a0Γb1 + a1Γb0 + 19Γ(a2Γb4 + a3Γb3 + a4Γb2) + r1 := mul64(a0, b1) + r1 = addMul64(r1, a1, b0) + r1 = addMul64(r1, a2_19, b4) + r1 = addMul64(r1, a3_19, b3) + r1 = addMul64(r1, a4_19, b2) + + // r2 = a0Γb2 + a1Γb1 + a2Γb0 + 19Γ(a3Γb4 + a4Γb3) + r2 := mul64(a0, b2) + r2 = addMul64(r2, a1, b1) + r2 = addMul64(r2, a2, b0) + r2 = addMul64(r2, a3_19, b4) + r2 = addMul64(r2, a4_19, b3) + + // r3 = a0Γb3 + a1Γb2 + a2Γb1 + a3Γb0 + 19Γa4Γb4 + r3 := mul64(a0, b3) + r3 = addMul64(r3, a1, b2) + r3 = addMul64(r3, a2, b1) + r3 = addMul64(r3, a3, b0) + r3 = addMul64(r3, a4_19, b4) + + // r4 = a0Γb4 + a1Γb3 + a2Γb2 + a3Γb1 + a4Γb0 + r4 := mul64(a0, b4) + r4 = addMul64(r4, a1, b3) + r4 = addMul64(r4, a2, b2) + r4 = addMul64(r4, a3, b1) + r4 = addMul64(r4, a4, b0) + + // After the multiplication, we need to reduce (carry) the five coefficients + // to obtain a result with limbs that are at most slightly larger than 2β΅ΒΉ, + // to respect the Element invariant. + // + // Overall, the reduction works the same as carryPropagate, except with + // wider inputs: we take the carry for each coefficient by shifting it right + // by 51, and add it to the limb above it. The top carry is multiplied by 19 + // according to the reduction identity and added to the lowest limb. + // + // The largest coefficient (r0) will be at most 111 bits, which guarantees + // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64. + // + // r0 = a0Γb0 + 19Γ(a1Γb4 + a2Γb3 + a3Γb2 + a4Γb1) + // r0 < 2β΅Β²Γ2β΅Β² + 19Γ(2β΅Β²Γ2β΅Β² + 2β΅Β²Γ2β΅Β² + 2β΅Β²Γ2β΅Β² + 2β΅Β²Γ2β΅Β²) + // r0 < (1 + 19 Γ 4) Γ 2β΅Β² Γ 2β΅Β² + // r0 < 2β· Γ 2β΅Β² Γ 2β΅Β² + // r0 < 2ΒΉΒΉΒΉ + // + // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most + // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and + // allows us to easily apply the reduction identity. + // + // r4 = a0Γb4 + a1Γb3 + a2Γb2 + a3Γb1 + a4Γb0 + // r4 < 5 Γ 2β΅Β² Γ 2β΅Β² + // r4 < 2ΒΉβ°β· + // + + c0 := shiftRightBy51(r0) + c1 := shiftRightBy51(r1) + c2 := shiftRightBy51(r2) + c3 := shiftRightBy51(r3) + c4 := shiftRightBy51(r4) + + rr0 := r0.lo&maskLow51Bits + c4*19 + rr1 := r1.lo&maskLow51Bits + c0 + rr2 := r2.lo&maskLow51Bits + c1 + rr3 := r3.lo&maskLow51Bits + c2 + rr4 := r4.lo&maskLow51Bits + c3 + + // Now all coefficients fit into 64-bit registers but are still too large to + // be passed around as a Element. We therefore do one last carry chain, + // where the carries will be small enough to fit in the wiggle room above 2β΅ΒΉ. + *v = Element{rr0, rr1, rr2, rr3, rr4} + v.carryPropagate() +} + +func feSquareGeneric(v, a *Element) { + l0 := a.l0 + l1 := a.l1 + l2 := a.l2 + l3 := a.l3 + l4 := a.l4 + + // Squaring works precisely like multiplication above, but thanks to its + // symmetry we get to group a few terms together. + // + // l4 l3 l2 l1 l0 x + // l4 l3 l2 l1 l0 = + // ------------------------ + // l4l0 l3l0 l2l0 l1l0 l0l0 + + // l4l1 l3l1 l2l1 l1l1 l0l1 + + // l4l2 l3l2 l2l2 l1l2 l0l2 + + // l4l3 l3l3 l2l3 l1l3 l0l3 + + // l4l4 l3l4 l2l4 l1l4 l0l4 = + // ---------------------------------------------- + // r8 r7 r6 r5 r4 r3 r2 r1 r0 + // + // l4l0 l3l0 l2l0 l1l0 l0l0 + + // l3l1 l2l1 l1l1 l0l1 19Γl4l1 + + // l2l2 l1l2 l0l2 19Γl4l2 19Γl3l2 + + // l1l3 l0l3 19Γl4l3 19Γl3l3 19Γl2l3 + + // l0l4 19Γl4l4 19Γl3l4 19Γl2l4 19Γl1l4 = + // -------------------------------------- + // r4 r3 r2 r1 r0 + // + // With precomputed 2Γ, 19Γ, and 2Γ19Γ terms, we can compute each limb with + // only three Mul64 and four Add64, instead of five and eight. + + l0_2 := l0 * 2 + l1_2 := l1 * 2 + + l1_38 := l1 * 38 + l2_38 := l2 * 38 + l3_38 := l3 * 38 + + l3_19 := l3 * 19 + l4_19 := l4 * 19 + + // r0 = l0Γl0 + 19Γ(l1Γl4 + l2Γl3 + l3Γl2 + l4Γl1) = l0Γl0 + 19Γ2Γ(l1Γl4 + l2Γl3) + r0 := mul64(l0, l0) + r0 = addMul64(r0, l1_38, l4) + r0 = addMul64(r0, l2_38, l3) + + // r1 = l0Γl1 + l1Γl0 + 19Γ(l2Γl4 + l3Γl3 + l4Γl2) = 2Γl0Γl1 + 19Γ2Γl2Γl4 + 19Γl3Γl3 + r1 := mul64(l0_2, l1) + r1 = addMul64(r1, l2_38, l4) + r1 = addMul64(r1, l3_19, l3) + + // r2 = l0Γl2 + l1Γl1 + l2Γl0 + 19Γ(l3Γl4 + l4Γl3) = 2Γl0Γl2 + l1Γl1 + 19Γ2Γl3Γl4 + r2 := mul64(l0_2, l2) + r2 = addMul64(r2, l1, l1) + r2 = addMul64(r2, l3_38, l4) + + // r3 = l0Γl3 + l1Γl2 + l2Γl1 + l3Γl0 + 19Γl4Γl4 = 2Γl0Γl3 + 2Γl1Γl2 + 19Γl4Γl4 + r3 := mul64(l0_2, l3) + r3 = addMul64(r3, l1_2, l2) + r3 = addMul64(r3, l4_19, l4) + + // r4 = l0Γl4 + l1Γl3 + l2Γl2 + l3Γl1 + l4Γl0 = 2Γl0Γl4 + 2Γl1Γl3 + l2Γl2 + r4 := mul64(l0_2, l4) + r4 = addMul64(r4, l1_2, l3) + r4 = addMul64(r4, l2, l2) + + c0 := shiftRightBy51(r0) + c1 := shiftRightBy51(r1) + c2 := shiftRightBy51(r2) + c3 := shiftRightBy51(r3) + c4 := shiftRightBy51(r4) + + rr0 := r0.lo&maskLow51Bits + c4*19 + rr1 := r1.lo&maskLow51Bits + c0 + rr2 := r2.lo&maskLow51Bits + c1 + rr3 := r3.lo&maskLow51Bits + c2 + rr4 := r4.lo&maskLow51Bits + c3 + + *v = Element{rr0, rr1, rr2, rr3, rr4} + v.carryPropagate() +} + +// carryPropagate brings the limbs below 52 bits by applying the reduction +// identity (a * 2Β²β΅β΅ + b = a * 19 + b) to the l4 carry. TODO inline +func (v *Element) carryPropagateGeneric() *Element { + c0 := v.l0 >> 51 + c1 := v.l1 >> 51 + c2 := v.l2 >> 51 + c3 := v.l3 >> 51 + c4 := v.l4 >> 51 + + v.l0 = v.l0&maskLow51Bits + c4*19 + v.l1 = v.l1&maskLow51Bits + c0 + v.l2 = v.l2&maskLow51Bits + c1 + v.l3 = v.l3&maskLow51Bits + c2 + v.l4 = v.l4&maskLow51Bits + c3 + + return v +} diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/bits_compat.go b/libgo/go/golang.org/x/crypto/internal/poly1305/bits_compat.go new file mode 100644 index 00000000000..45b5c966b2b --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/bits_compat.go @@ -0,0 +1,40 @@ +// 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. + +//go:build !go1.13 +// +build !go1.13 + +package poly1305 + +// Generic fallbacks for the math/bits intrinsics, copied from +// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had +// variable time fallbacks until Go 1.13. + +func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { + sum = x + y + carry + carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 + return +} + +func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { + diff = x - y - borrow + borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 + return +} + +func bitsMul64(x, y uint64) (hi, lo uint64) { + const mask32 = 1<<32 - 1 + x0 := x & mask32 + x1 := x >> 32 + y0 := y & mask32 + y1 := y >> 32 + w0 := x0 * y0 + t := x1*y0 + w0>>32 + w1 := t & mask32 + w2 := t >> 32 + w1 += x0 * y1 + hi = x1*y1 + w2 + w1>>32 + lo = x * y + return +} diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/bits_go1.13.go b/libgo/go/golang.org/x/crypto/internal/poly1305/bits_go1.13.go new file mode 100644 index 00000000000..ed52b3418ab --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/bits_go1.13.go @@ -0,0 +1,22 @@ +// 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. + +//go:build go1.13 +// +build go1.13 + +package poly1305 + +import "math/bits" + +func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { + return bits.Add64(x, y, carry) +} + +func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { + return bits.Sub64(x, y, borrow) +} + +func bitsMul64(x, y uint64) (hi, lo uint64) { + return bits.Mul64(x, y) +} diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/libgo/go/golang.org/x/crypto/internal/poly1305/mac_noasm.go new file mode 100644 index 00000000000..f184b67d98d --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/mac_noasm.go @@ -0,0 +1,10 @@ +// Copyright 2018 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. + +//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego +// +build !amd64,!ppc64le,!s390x !gc purego + +package poly1305 + +type mac struct{ macGeneric } diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/poly1305.go b/libgo/go/golang.org/x/crypto/internal/poly1305/poly1305.go new file mode 100644 index 00000000000..4aaea810a26 --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/poly1305.go @@ -0,0 +1,99 @@ +// Copyright 2012 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 poly1305 implements Poly1305 one-time message authentication code as +// specified in https://cr.yp.to/mac/poly1305-20050329.pdf. +// +// Poly1305 is a fast, one-time authentication function. It is infeasible for an +// attacker to generate an authenticator for a message without the key. However, a +// key must only be used for a single message. Authenticating two different +// messages with the same key allows an attacker to forge authenticators for other +// messages with the same key. +// +// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was +// used with a fixed key in order to generate one-time keys from an nonce. +// However, in this package AES isn't used and the one-time key is specified +// directly. +package poly1305 + +import "crypto/subtle" + +// TagSize is the size, in bytes, of a poly1305 authenticator. +const TagSize = 16 + +// Sum generates an authenticator for msg using a one-time key and puts the +// 16-byte result into out. Authenticating two different messages with the same +// key allows an attacker to forge messages at will. +func Sum(out *[16]byte, m []byte, key *[32]byte) { + h := New(key) + h.Write(m) + h.Sum(out[:0]) +} + +// Verify returns true if mac is a valid authenticator for m with the given key. +func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { + var tmp [16]byte + Sum(&tmp, m, key) + return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 +} + +// New returns a new MAC computing an authentication +// tag of all data written to it with the given key. +// This allows writing the message progressively instead +// of passing it as a single slice. Common users should use +// the Sum function instead. +// +// The key must be unique for each message, as authenticating +// two different messages with the same key allows an attacker +// to forge messages at will. +func New(key *[32]byte) *MAC { + m := &MAC{} + initialize(key, &m.macState) + return m +} + +// MAC is an io.Writer computing an authentication tag +// of the data written to it. +// +// MAC cannot be used like common hash.Hash implementations, +// because using a poly1305 key twice breaks its security. +// Therefore writing data to a running MAC after calling +// Sum or Verify causes it to panic. +type MAC struct { + mac // platform-dependent implementation + + finalized bool +} + +// Size returns the number of bytes Sum will return. +func (h *MAC) Size() int { return TagSize } + +// Write adds more data to the running message authentication code. +// It never returns an error. +// +// It must not be called after the first call of Sum or Verify. +func (h *MAC) Write(p []byte) (n int, err error) { + if h.finalized { + panic("poly1305: write to MAC after Sum or Verify") + } + return h.mac.Write(p) +} + +// Sum computes the authenticator of all data written to the +// message authentication code. +func (h *MAC) Sum(b []byte) []byte { + var mac [TagSize]byte + h.mac.Sum(&mac) + h.finalized = true + return append(b, mac[:]...) +} + +// Verify returns whether the authenticator of all data written to +// the message authentication code matches the expected value. +func (h *MAC) Verify(expected []byte) bool { + var mac [TagSize]byte + h.mac.Sum(&mac) + h.finalized = true + return subtle.ConstantTimeCompare(expected, mac[:]) == 1 +} diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/sum_amd64.go b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_amd64.go new file mode 100644 index 00000000000..6d522333f29 --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_amd64.go @@ -0,0 +1,48 @@ +// Copyright 2012 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. + +//go:build gc && !purego +// +build gc,!purego + +package poly1305 + +//go:noescape +func update(state *macState, msg []byte) + +// mac is a wrapper for macGeneric that redirects calls that would have gone to +// updateGeneric to update. +// +// Its Write and Sum methods are otherwise identical to the macGeneric ones, but +// using function pointers would carry a major performance cost. +type mac struct{ macGeneric } + +func (h *mac) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < TagSize { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + update(&h.macState, h.buffer[:]) + } + if n := len(p) - (len(p) % TagSize); n > 0 { + update(&h.macState, p[:n]) + p = p[n:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return nn, nil +} + +func (h *mac) Sum(out *[16]byte) { + state := h.macState + if h.offset > 0 { + update(&state, h.buffer[:h.offset]) + } + finalize(out, &state.h, &state.s) +} diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/sum_generic.go b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_generic.go new file mode 100644 index 00000000000..c942a65904f --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_generic.go @@ -0,0 +1,310 @@ +// Copyright 2018 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. + +// This file provides the generic implementation of Sum and MAC. Other files +// might provide optimized assembly implementations of some of this code. + +package poly1305 + +import "encoding/binary" + +// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag +// for a 64 bytes message is approximately +// +// s + m[0:16] * rβ΄ + m[16:32] * rΒ³ + m[32:48] * rΒ² + m[48:64] * r mod 2ΒΉΒ³β° - 5 +// +// for some secret r and s. It can be computed sequentially like +// +// for len(msg) > 0: +// h += read(msg, 16) +// h *= r +// h %= 2ΒΉΒ³β° - 5 +// return h + s +// +// All the complexity is about doing performant constant-time math on numbers +// larger than any available numeric type. + +func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { + h := newMACGeneric(key) + h.Write(msg) + h.Sum(out) +} + +func newMACGeneric(key *[32]byte) macGeneric { + m := macGeneric{} + initialize(key, &m.macState) + return m +} + +// macState holds numbers in saturated 64-bit little-endian limbs. That is, +// the value of [x0, x1, x2] is x[0] + x[1] * 2βΆβ΄ + x[2] * 2ΒΉΒ²βΈ. +type macState struct { + // h is the main accumulator. It is to be interpreted modulo 2ΒΉΒ³β° - 5, but + // can grow larger during and after rounds. It must, however, remain below + // 2 * (2ΒΉΒ³β° - 5). + h [3]uint64 + // r and s are the private key components. + r [2]uint64 + s [2]uint64 +} + +type macGeneric struct { + macState + + buffer [TagSize]byte + offset int +} + +// Write splits the incoming message into TagSize chunks, and passes them to +// update. It buffers incomplete chunks. +func (h *macGeneric) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < TagSize { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + updateGeneric(&h.macState, h.buffer[:]) + } + if n := len(p) - (len(p) % TagSize); n > 0 { + updateGeneric(&h.macState, p[:n]) + p = p[n:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return nn, nil +} + +// Sum flushes the last incomplete chunk from the buffer, if any, and generates +// the MAC output. It does not modify its state, in order to allow for multiple +// calls to Sum, even if no Write is allowed after Sum. +func (h *macGeneric) Sum(out *[TagSize]byte) { + state := h.macState + if h.offset > 0 { + updateGeneric(&state, h.buffer[:h.offset]) + } + finalize(out, &state.h, &state.s) +} + +// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It +// clears some bits of the secret coefficient to make it possible to implement +// multiplication more efficiently. +const ( + rMask0 = 0x0FFFFFFC0FFFFFFF + rMask1 = 0x0FFFFFFC0FFFFFFC +) + +// initialize loads the 256-bit key into the two 128-bit secret values r and s. +func initialize(key *[32]byte, m *macState) { + m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0 + m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1 + m.s[0] = binary.LittleEndian.Uint64(key[16:24]) + m.s[1] = binary.LittleEndian.Uint64(key[24:32]) +} + +// uint128 holds a 128-bit number as two 64-bit limbs, for use with the +// bits.Mul64 and bits.Add64 intrinsics. +type uint128 struct { + lo, hi uint64 +} + +func mul64(a, b uint64) uint128 { + hi, lo := bitsMul64(a, b) + return uint128{lo, hi} +} + +func add128(a, b uint128) uint128 { + lo, c := bitsAdd64(a.lo, b.lo, 0) + hi, c := bitsAdd64(a.hi, b.hi, c) + if c != 0 { + panic("poly1305: unexpected overflow") + } + return uint128{lo, hi} +} + +func shiftRightBy2(a uint128) uint128 { + a.lo = a.lo>>2 | (a.hi&3)<<62 + a.hi = a.hi >> 2 + return a +} + +// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of +// 128 bits of message, it computes +// +// hβ = (h + m) * r mod 2ΒΉΒ³β° - 5 +// +// If the msg length is not a multiple of TagSize, it assumes the last +// incomplete chunk is the final one. +func updateGeneric(state *macState, msg []byte) { + h0, h1, h2 := state.h[0], state.h[1], state.h[2] + r0, r1 := state.r[0], state.r[1] + + for len(msg) > 0 { + var c uint64 + + // For the first step, h + m, we use a chain of bits.Add64 intrinsics. + // The resulting value of h might exceed 2ΒΉΒ³β° - 5, but will be partially + // reduced at the end of the multiplication below. + // + // The spec requires us to set a bit just above the message size, not to + // hide leading zeroes. For full chunks, that's 1 << 128, so we can just + // add 1 to the most significant (2ΒΉΒ²βΈ) limb, h2. + if len(msg) >= TagSize { + h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) + h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) + h2 += c + 1 + + msg = msg[TagSize:] + } else { + var buf [TagSize]byte + copy(buf[:], msg) + buf[len(msg)] = 1 + + h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) + h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) + h2 += c + + msg = nil + } + + // Multiplication of big number limbs is similar to elementary school + // columnar multiplication. Instead of digits, there are 64-bit limbs. + // + // We are multiplying a 3 limbs number, h, by a 2 limbs number, r. + // + // h2 h1 h0 x + // r1 r0 = + // ---------------- + // h2r0 h1r0 h0r0 <-- individual 128-bit products + // + h2r1 h1r1 h0r1 + // ------------------------ + // m3 m2 m1 m0 <-- result in 128-bit overlapping limbs + // ------------------------ + // m3.hi m2.hi m1.hi m0.hi <-- carry propagation + // + m3.lo m2.lo m1.lo m0.lo + // ------------------------------- + // t4 t3 t2 t1 t0 <-- final result in 64-bit limbs + // + // The main difference from pen-and-paper multiplication is that we do + // carry propagation in a separate step, as if we wrote two digit sums + // at first (the 128-bit limbs), and then carried the tens all at once. + + h0r0 := mul64(h0, r0) + h1r0 := mul64(h1, r0) + h2r0 := mul64(h2, r0) + h0r1 := mul64(h0, r1) + h1r1 := mul64(h1, r1) + h2r1 := mul64(h2, r1) + + // Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their + // top 4 bits cleared by rMask{0,1}, we know that their product is not going + // to overflow 64 bits, so we can ignore the high part of the products. + // + // This also means that the product doesn't have a fifth limb (t4). + if h2r0.hi != 0 { + panic("poly1305: unexpected overflow") + } + if h2r1.hi != 0 { + panic("poly1305: unexpected overflow") + } + + m0 := h0r0 + m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again + m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1. + m3 := h2r1 + + t0 := m0.lo + t1, c := bitsAdd64(m1.lo, m0.hi, 0) + t2, c := bitsAdd64(m2.lo, m1.hi, c) + t3, _ := bitsAdd64(m3.lo, m2.hi, c) + + // Now we have the result as 4 64-bit limbs, and we need to reduce it + // modulo 2ΒΉΒ³β° - 5. The special shape of this Crandall prime lets us do + // a cheap partial reduction according to the reduction identity + // + // c * 2ΒΉΒ³β° + n = c * 5 + n mod 2ΒΉΒ³β° - 5 + // + // because 2ΒΉΒ³β° = 5 mod 2ΒΉΒ³β° - 5. Partial reduction since the result is + // likely to be larger than 2ΒΉΒ³β° - 5, but still small enough to fit the + // assumptions we make about h in the rest of the code. + // + // See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23 + + // We split the final result at the 2ΒΉΒ³β° mark into h and cc, the carry. + // Note that the carry bits are effectively shifted left by 2, in other + // words, cc = c * 4 for the c in the reduction identity. + h0, h1, h2 = t0, t1, t2&maskLow2Bits + cc := uint128{t2 & maskNotLow2Bits, t3} + + // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. + + h0, c = bitsAdd64(h0, cc.lo, 0) + h1, c = bitsAdd64(h1, cc.hi, c) + h2 += c + + cc = shiftRightBy2(cc) + + h0, c = bitsAdd64(h0, cc.lo, 0) + h1, c = bitsAdd64(h1, cc.hi, c) + h2 += c + + // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most + // + // 5 * 2ΒΉΒ²βΈ + (2ΒΉΒ²βΈ - 1) = 6 * 2ΒΉΒ²βΈ - 1 + } + + state.h[0], state.h[1], state.h[2] = h0, h1, h2 +} + +const ( + maskLow2Bits uint64 = 0x0000000000000003 + maskNotLow2Bits uint64 = ^maskLow2Bits +) + +// select64 returns x if v == 1 and y if v == 0, in constant time. +func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y } + +// [p0, p1, p2] is 2ΒΉΒ³β° - 5 in little endian order. +const ( + p0 = 0xFFFFFFFFFFFFFFFB + p1 = 0xFFFFFFFFFFFFFFFF + p2 = 0x0000000000000003 +) + +// finalize completes the modular reduction of h and computes +// +// out = h + s mod 2ΒΉΒ²βΈ +// +func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { + h0, h1, h2 := h[0], h[1], h[2] + + // After the partial reduction in updateGeneric, h might be more than + // 2ΒΉΒ³β° - 5, but will be less than 2 * (2ΒΉΒ³β° - 5). To complete the reduction + // in constant time, we compute t = h - (2ΒΉΒ³β° - 5), and select h as the + // result if the subtraction underflows, and t otherwise. + + hMinusP0, b := bitsSub64(h0, p0, 0) + hMinusP1, b := bitsSub64(h1, p1, b) + _, b = bitsSub64(h2, p2, b) + + // h = h if h < p else h - p + h0 = select64(b, h0, hMinusP0) + h1 = select64(b, h1, hMinusP1) + + // Finally, we compute the last Poly1305 step + // + // tag = h + s mod 2ΒΉΒ²βΈ + // + // by just doing a wide addition with the 128 low bits of h and discarding + // the overflow. + h0, c := bitsAdd64(h0, s[0], 0) + h1, _ = bitsAdd64(h1, s[1], c) + + binary.LittleEndian.PutUint64(out[0:8], h0) + binary.LittleEndian.PutUint64(out[8:16], h1) +} diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go new file mode 100644 index 00000000000..4a069941a6e --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go @@ -0,0 +1,48 @@ +// 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. + +//go:build gc && !purego +// +build gc,!purego + +package poly1305 + +//go:noescape +func update(state *macState, msg []byte) + +// mac is a wrapper for macGeneric that redirects calls that would have gone to +// updateGeneric to update. +// +// Its Write and Sum methods are otherwise identical to the macGeneric ones, but +// using function pointers would carry a major performance cost. +type mac struct{ macGeneric } + +func (h *mac) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < TagSize { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + update(&h.macState, h.buffer[:]) + } + if n := len(p) - (len(p) % TagSize); n > 0 { + update(&h.macState, p[:n]) + p = p[n:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return nn, nil +} + +func (h *mac) Sum(out *[16]byte) { + state := h.macState + if h.offset > 0 { + update(&state, h.buffer[:h.offset]) + } + finalize(out, &state.h, &state.s) +} diff --git a/libgo/go/golang.org/x/crypto/internal/poly1305/sum_s390x.go b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_s390x.go new file mode 100644 index 00000000000..62cc9f84709 --- /dev/null +++ b/libgo/go/golang.org/x/crypto/internal/poly1305/sum_s390x.go @@ -0,0 +1,76 @@ +// Copyright 2018 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. + +//go:build gc && !purego +// +build gc,!purego + +package poly1305 + +import ( + "golang.org/x/sys/cpu" +) + +// updateVX is an assembly implementation of Poly1305 that uses vector +// instructions. It must only be called if the vector facility (vx) is +// available. +//go:noescape +func updateVX(state *macState, msg []byte) + +// mac is a replacement for macGeneric that uses a larger buffer and redirects +// calls that would have gone to updateGeneric to updateVX if the vector +// facility is installed. +// +// A larger buffer is required for good performance because the vector +// implementation has a higher fixed cost per call than the generic +// implementation. +type mac struct { + macState + + buffer [16 * TagSize]byte // size must be a multiple of block size (16) + offset int +} + +func (h *mac) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < len(h.buffer) { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + if cpu.S390X.HasVX { + updateVX(&h.macState, h.buffer[:]) + } else { + updateGeneric(&h.macState, h.buffer[:]) + } + } + + tail := len(p) % len(h.buffer) // number of bytes to copy into buffer + body := len(p) - tail // number of bytes to process now + if body > 0 { + if cpu.S390X.HasVX { + updateVX(&h.macState, p[:body]) + } else { + updateGeneric(&h.macState, p[:body]) + } + } + h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0 + return nn, nil +} + +func (h *mac) Sum(out *[TagSize]byte) { + state := h.macState + remainder := h.buffer[:h.offset] + + // Use the generic implementation if we have 2 or fewer blocks left + // to sum. The vector implementation has a higher startup time. + if cpu.S390X.HasVX && len(remainder) > 2*TagSize { + updateVX(&state, remainder) + } else if len(remainder) > 0 { + updateGeneric(&state, remainder) + } + finalize(out, &state.h, &state.s) +} diff --git a/libgo/go/golang.org/x/mod/modfile/rule.go b/libgo/go/golang.org/x/mod/modfile/rule.go index 78f83fa7144..ed2f31aa70e 100644 --- a/libgo/go/golang.org/x/mod/modfile/rule.go +++ b/libgo/go/golang.org/x/mod/modfile/rule.go @@ -423,68 +423,12 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a } case "replace": - arrow := 2 - if len(args) >= 2 && args[1] == "=>" { - arrow = 1 - } - if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" { - errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb) - return - } - s, err := parseString(&args[0]) - if err != nil { - errorf("invalid quoted string: %v", err) - return - } - pathMajor, err := modulePathMajor(s) - if err != nil { - wrapModPathError(s, err) - return - } - var v string - if arrow == 2 { - v, err = parseVersion(verb, s, &args[1], fix) - if err != nil { - wrapError(err) - return - } - if err := module.CheckPathMajor(v, pathMajor); err != nil { - wrapModPathError(s, err) - return - } - } - ns, err := parseString(&args[arrow+1]) - if err != nil { - errorf("invalid quoted string: %v", err) + replace, wrappederr := parseReplace(f.Syntax.Name, line, verb, args, fix) + if wrappederr != nil { + *errs = append(*errs, *wrappederr) return } - nv := "" - if len(args) == arrow+2 { - if !IsDirectoryPath(ns) { - errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)") - return - } - if filepath.Separator == '/' && strings.Contains(ns, `\`) { - errorf("replacement directory appears to be Windows path (on a non-windows system)") - return - } - } - if len(args) == arrow+3 { - nv, err = parseVersion(verb, ns, &args[arrow+2], fix) - if err != nil { - wrapError(err) - return - } - if IsDirectoryPath(ns) { - errorf("replacement module directory path %q cannot have version", ns) - return - } - } - f.Replace = append(f.Replace, &Replace{ - Old: module.Version{Path: s, Version: v}, - New: module.Version{Path: ns, Version: nv}, - Syntax: line, - }) + f.Replace = append(f.Replace, replace) case "retract": rationale := parseDirectiveComment(block, line) @@ -515,6 +459,83 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a } } +func parseReplace(filename string, line *Line, verb string, args []string, fix VersionFixer) (*Replace, *Error) { + wrapModPathError := func(modPath string, err error) *Error { + return &Error{ + Filename: filename, + Pos: line.Start, + ModPath: modPath, + Verb: verb, + Err: err, + } + } + wrapError := func(err error) *Error { + return &Error{ + Filename: filename, + Pos: line.Start, + Err: err, + } + } + errorf := func(format string, args ...interface{}) *Error { + return wrapError(fmt.Errorf(format, args...)) + } + + arrow := 2 + if len(args) >= 2 && args[1] == "=>" { + arrow = 1 + } + if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" { + return nil, errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb) + } + s, err := parseString(&args[0]) + if err != nil { + return nil, errorf("invalid quoted string: %v", err) + } + pathMajor, err := modulePathMajor(s) + if err != nil { + return nil, wrapModPathError(s, err) + + } + var v string + if arrow == 2 { + v, err = parseVersion(verb, s, &args[1], fix) + if err != nil { + return nil, wrapError(err) + } + if err := module.CheckPathMajor(v, pathMajor); err != nil { + return nil, wrapModPathError(s, err) + } + } + ns, err := parseString(&args[arrow+1]) + if err != nil { + return nil, errorf("invalid quoted string: %v", err) + } + nv := "" + if len(args) == arrow+2 { + if !IsDirectoryPath(ns) { + return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)") + } + if filepath.Separator == '/' && strings.Contains(ns, `\`) { + return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)") + } + } + if len(args) == arrow+3 { + nv, err = parseVersion(verb, ns, &args[arrow+2], fix) + if err != nil { + return nil, wrapError(err) + } + if IsDirectoryPath(ns) { + return nil, errorf("replacement module directory path %q cannot have version", ns) + + } + } + return &Replace{ + Old: module.Version{Path: s, Version: v}, + New: module.Version{Path: ns, Version: nv}, + Syntax: line, + }, nil +} + // fixRetract applies fix to each retract directive in f, appending any errors // to errs. // @@ -556,6 +577,63 @@ func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) { } } +func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, fix VersionFixer) { + wrapError := func(err error) { + *errs = append(*errs, Error{ + Filename: f.Syntax.Name, + Pos: line.Start, + Err: err, + }) + } + errorf := func(format string, args ...interface{}) { + wrapError(fmt.Errorf(format, args...)) + } + + switch verb { + default: + errorf("unknown directive: %s", verb) + + case "go": + if f.Go != nil { + errorf("repeated go statement") + return + } + if len(args) != 1 { + errorf("go directive expects exactly one argument") + return + } else if !GoVersionRE.MatchString(args[0]) { + errorf("invalid go version '%s': must match format 1.23", args[0]) + return + } + + f.Go = &Go{Syntax: line} + f.Go.Version = args[0] + + case "use": + if len(args) != 1 { + errorf("usage: %s local/dir", verb) + return + } + s, err := parseString(&args[0]) + if err != nil { + errorf("invalid quoted string: %v", err) + return + } + f.Use = append(f.Use, &Use{ + Path: s, + Syntax: line, + }) + + case "replace": + replace, wrappederr := parseReplace(f.Syntax.Name, line, verb, args, fix) + if wrappederr != nil { + *errs = append(*errs, *wrappederr) + return + } + f.Replace = append(f.Replace, replace) + } +} + // IsDirectoryPath reports whether the given path should be interpreted // as a directory path. Just like on the go command line, relative paths // and rooted paths are directory paths; the rest are module paths. @@ -956,170 +1034,217 @@ func (f *File) SetRequire(req []*Require) { // SetRequireSeparateIndirect updates the requirements of f to contain the given // requirements. Comment contents (except for 'indirect' markings) are retained -// from the first existing requirement for each module path, and block structure -// is maintained as long as the indirect markings match. +// from the first existing requirement for each module path. Like SetRequire, +// SetRequireSeparateIndirect adds requirements for new paths in req, +// updates the version and "// indirect" comment on existing requirements, +// and deletes requirements on paths not in req. Existing duplicate requirements +// are deleted. // -// Any requirements on paths not already present in the file are added. Direct -// requirements are added to the last block containing *any* other direct -// requirement. Indirect requirements are added to the last block containing -// *only* other indirect requirements. If no suitable block exists, a new one is -// added, with the last block containing a direct dependency (if any) -// immediately before the first block containing only indirect dependencies. +// As its name suggests, SetRequireSeparateIndirect puts direct and indirect +// requirements into two separate blocks, one containing only direct +// requirements, and the other containing only indirect requirements. +// SetRequireSeparateIndirect may move requirements between these two blocks +// when their indirect markings change. However, SetRequireSeparateIndirect +// won't move requirements from other blocks, especially blocks with comments. // -// The Syntax field is ignored for requirements in the given blocks. +// If the file initially has one uncommented block of requirements, +// SetRequireSeparateIndirect will split it into a direct-only and indirect-only +// block. This aids in the transition to separate blocks. func (f *File) SetRequireSeparateIndirect(req []*Require) { - type modKey struct { - path string - indirect bool - } - need := make(map[modKey]string) - for _, r := range req { - need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version + // hasComments returns whether a line or block has comments + // other than "indirect". + hasComments := func(c Comments) bool { + return len(c.Before) > 0 || len(c.After) > 0 || len(c.Suffix) > 1 || + (len(c.Suffix) == 1 && + strings.TrimSpace(strings.TrimPrefix(c.Suffix[0].Token, string(slashSlash))) != "indirect") } - comments := make(map[string]Comments) - for _, r := range f.Require { - v, ok := need[modKey{r.Mod.Path, r.Indirect}] - if !ok { - if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok { - if _, dup := comments[r.Mod.Path]; !dup { - comments[r.Mod.Path] = r.Syntax.Comments - } + // moveReq adds r to block. If r was in another block, moveReq deletes + // it from that block and transfers its comments. + moveReq := func(r *Require, block *LineBlock) { + var line *Line + if r.Syntax == nil { + line = &Line{Token: []string{AutoQuote(r.Mod.Path), r.Mod.Version}} + r.Syntax = line + if r.Indirect { + r.setIndirect(true) } - r.markRemoved() - continue + } else { + line = new(Line) + *line = *r.Syntax + if !line.InBlock && len(line.Token) > 0 && line.Token[0] == "require" { + line.Token = line.Token[1:] + } + r.Syntax.Token = nil // Cleanup will delete the old line. + r.Syntax = line } - r.setVersion(v) - delete(need, modKey{r.Mod.Path, r.Indirect}) + line.InBlock = true + block.Line = append(block.Line, line) } + // Examine existing require lines and blocks. var ( - lastDirectOrMixedBlock Expr - firstIndirectOnlyBlock Expr - lastIndirectOnlyBlock Expr + // We may insert new requirements into the last uncommented + // direct-only and indirect-only blocks. We may also move requirements + // to the opposite block if their indirect markings change. + lastDirectIndex = -1 + lastIndirectIndex = -1 + + // If there are no direct-only or indirect-only blocks, a new block may + // be inserted after the last require line or block. + lastRequireIndex = -1 + + // If there's only one require line or block, and it's uncommented, + // we'll move its requirements to the direct-only or indirect-only blocks. + requireLineOrBlockCount = 0 + + // Track the block each requirement belongs to (if any) so we can + // move them later. + lineToBlock = make(map[*Line]*LineBlock) ) - for _, stmt := range f.Syntax.Stmt { + for i, stmt := range f.Syntax.Stmt { switch stmt := stmt.(type) { case *Line: if len(stmt.Token) == 0 || stmt.Token[0] != "require" { continue } - if isIndirect(stmt) { - lastIndirectOnlyBlock = stmt - } else { - lastDirectOrMixedBlock = stmt + lastRequireIndex = i + requireLineOrBlockCount++ + if !hasComments(stmt.Comments) { + if isIndirect(stmt) { + lastIndirectIndex = i + } else { + lastDirectIndex = i + } } + case *LineBlock: if len(stmt.Token) == 0 || stmt.Token[0] != "require" { continue } - indirectOnly := true + lastRequireIndex = i + requireLineOrBlockCount++ + allDirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments) + allIndirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments) for _, line := range stmt.Line { - if len(line.Token) == 0 { - continue - } - if !isIndirect(line) { - indirectOnly = false - break + lineToBlock[line] = stmt + if hasComments(line.Comments) { + allDirect = false + allIndirect = false + } else if isIndirect(line) { + allDirect = false + } else { + allIndirect = false } } - if indirectOnly { - lastIndirectOnlyBlock = stmt - if firstIndirectOnlyBlock == nil { - firstIndirectOnlyBlock = stmt - } - } else { - lastDirectOrMixedBlock = stmt + if allDirect { + lastDirectIndex = i + } + if allIndirect { + lastIndirectIndex = i } } } - isOrContainsStmt := func(stmt Expr, target Expr) bool { - if stmt == target { - return true - } - if stmt, ok := stmt.(*LineBlock); ok { - if target, ok := target.(*Line); ok { - for _, line := range stmt.Line { - if line == target { - return true - } - } + oneFlatUncommentedBlock := requireLineOrBlockCount == 1 && + !hasComments(*f.Syntax.Stmt[lastRequireIndex].Comment()) + + // Create direct and indirect blocks if needed. Convert lines into blocks + // if needed. If we end up with an empty block or a one-line block, + // Cleanup will delete it or convert it to a line later. + insertBlock := func(i int) *LineBlock { + block := &LineBlock{Token: []string{"require"}} + f.Syntax.Stmt = append(f.Syntax.Stmt, nil) + copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) + f.Syntax.Stmt[i] = block + return block + } + + ensureBlock := func(i int) *LineBlock { + switch stmt := f.Syntax.Stmt[i].(type) { + case *LineBlock: + return stmt + case *Line: + block := &LineBlock{ + Token: []string{"require"}, + Line: []*Line{stmt}, } + stmt.Token = stmt.Token[1:] // remove "require" + stmt.InBlock = true + f.Syntax.Stmt[i] = block + return block + default: + panic(fmt.Sprintf("unexpected statement: %v", stmt)) } - return false } - addRequire := func(path, vers string, indirect bool, comments Comments) { - var line *Line - if indirect { - if lastIndirectOnlyBlock != nil { - line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers) - } else { - // Add a new require block after the last direct-only or mixed "require" - // block (if any). - // - // (f.Syntax.addLine would add the line to an existing "require" block if - // present, but here the existing "require" blocks are all direct-only, so - // we know we need to add a new block instead.) - line = &Line{Token: []string{"require", path, vers}} - lastIndirectOnlyBlock = line - firstIndirectOnlyBlock = line // only block implies first block - if lastDirectOrMixedBlock == nil { - f.Syntax.Stmt = append(f.Syntax.Stmt, line) - } else { - for i, stmt := range f.Syntax.Stmt { - if isOrContainsStmt(stmt, lastDirectOrMixedBlock) { - f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size - copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up - f.Syntax.Stmt[i+1] = line - break - } - } - } - } + var lastDirectBlock *LineBlock + if lastDirectIndex < 0 { + if lastIndirectIndex >= 0 { + lastDirectIndex = lastIndirectIndex + lastIndirectIndex++ + } else if lastRequireIndex >= 0 { + lastDirectIndex = lastRequireIndex + 1 } else { - if lastDirectOrMixedBlock != nil { - line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers) - } else { - // Add a new require block before the first indirect block (if any). - // - // That way if the file initially contains only indirect lines, - // the direct lines still appear before it: we preserve existing - // structure, but only to the extent that that structure already - // reflects the direct/indirect split. - line = &Line{Token: []string{"require", path, vers}} - lastDirectOrMixedBlock = line - if firstIndirectOnlyBlock == nil { - f.Syntax.Stmt = append(f.Syntax.Stmt, line) - } else { - for i, stmt := range f.Syntax.Stmt { - if isOrContainsStmt(stmt, firstIndirectOnlyBlock) { - f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size - copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up - f.Syntax.Stmt[i] = line - break - } - } - } - } + lastDirectIndex = len(f.Syntax.Stmt) } + lastDirectBlock = insertBlock(lastDirectIndex) + } else { + lastDirectBlock = ensureBlock(lastDirectIndex) + } - line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before) - line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix) + var lastIndirectBlock *LineBlock + if lastIndirectIndex < 0 { + lastIndirectIndex = lastDirectIndex + 1 + lastIndirectBlock = insertBlock(lastIndirectIndex) + } else { + lastIndirectBlock = ensureBlock(lastIndirectIndex) + } - r := &Require{ - Mod: module.Version{Path: path, Version: vers}, - Indirect: indirect, - Syntax: line, + // Delete requirements we don't want anymore. + // Update versions and indirect comments on requirements we want to keep. + // If a requirement is in last{Direct,Indirect}Block with the wrong + // indirect marking after this, or if the requirement is in an single + // uncommented mixed block (oneFlatUncommentedBlock), move it to the + // correct block. + // + // Some blocks may be empty after this. Cleanup will remove them. + need := make(map[string]*Require) + for _, r := range req { + need[r.Mod.Path] = r + } + have := make(map[string]*Require) + for _, r := range f.Require { + path := r.Mod.Path + if need[path] == nil || have[path] != nil { + // Requirement not needed, or duplicate requirement. Delete. + r.markRemoved() + continue + } + have[r.Mod.Path] = r + r.setVersion(need[path].Mod.Version) + r.setIndirect(need[path].Indirect) + if need[path].Indirect && + (oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastDirectBlock) { + moveReq(r, lastIndirectBlock) + } else if !need[path].Indirect && + (oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastIndirectBlock) { + moveReq(r, lastDirectBlock) } - r.setIndirect(indirect) - f.Require = append(f.Require, r) } - for k, vers := range need { - addRequire(k.path, vers, k.indirect, comments[k.path]) + // Add new requirements. + for path, r := range need { + if have[path] == nil { + if r.Indirect { + moveReq(r, lastIndirectBlock) + } else { + moveReq(r, lastDirectBlock) + } + f.Require = append(f.Require, r) + } } + f.SortBlocks() } @@ -1165,6 +1290,10 @@ func (f *File) DropExclude(path, vers string) error { } func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { + return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers) +} + +func addReplace(syntax *FileSyntax, replace *[]*Replace, oldPath, oldVers, newPath, newVers string) error { need := true old := module.Version{Path: oldPath, Version: oldVers} new := module.Version{Path: newPath, Version: newVers} @@ -1178,12 +1307,12 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { } var hint *Line - for _, r := range f.Replace { + for _, r := range *replace { if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) { if need { // Found replacement for old; update to use new. r.New = new - f.Syntax.updateLine(r.Syntax, tokens...) + syntax.updateLine(r.Syntax, tokens...) need = false continue } @@ -1196,7 +1325,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { } } if need { - f.Replace = append(f.Replace, &Replace{Old: old, New: new, Syntax: f.Syntax.addLine(hint, tokens...)}) + *replace = append(*replace, &Replace{Old: old, New: new, Syntax: syntax.addLine(hint, tokens...)}) } return nil } @@ -1282,30 +1411,36 @@ func (f *File) SortBlocks() { // retract directives are not de-duplicated since comments are // meaningful, and versions may be retracted multiple times. func (f *File) removeDups() { + removeDups(f.Syntax, &f.Exclude, &f.Replace) +} + +func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace) { kill := make(map[*Line]bool) // Remove duplicate excludes. - haveExclude := make(map[module.Version]bool) - for _, x := range f.Exclude { - if haveExclude[x.Mod] { - kill[x.Syntax] = true - continue + if exclude != nil { + haveExclude := make(map[module.Version]bool) + for _, x := range *exclude { + if haveExclude[x.Mod] { + kill[x.Syntax] = true + continue + } + haveExclude[x.Mod] = true } - haveExclude[x.Mod] = true - } - var excl []*Exclude - for _, x := range f.Exclude { - if !kill[x.Syntax] { - excl = append(excl, x) + var excl []*Exclude + for _, x := range *exclude { + if !kill[x.Syntax] { + excl = append(excl, x) + } } + *exclude = excl } - f.Exclude = excl // Remove duplicate replacements. // Later replacements take priority over earlier ones. haveReplace := make(map[module.Version]bool) - for i := len(f.Replace) - 1; i >= 0; i-- { - x := f.Replace[i] + for i := len(*replace) - 1; i >= 0; i-- { + x := (*replace)[i] if haveReplace[x.Old] { kill[x.Syntax] = true continue @@ -1313,18 +1448,18 @@ func (f *File) removeDups() { haveReplace[x.Old] = true } var repl []*Replace - for _, x := range f.Replace { + for _, x := range *replace { if !kill[x.Syntax] { repl = append(repl, x) } } - f.Replace = repl + *replace = repl // Duplicate require and retract directives are not removed. // Drop killed statements from the syntax tree. var stmts []Expr - for _, stmt := range f.Syntax.Stmt { + for _, stmt := range syntax.Stmt { switch stmt := stmt.(type) { case *Line: if kill[stmt] { @@ -1344,7 +1479,7 @@ func (f *File) removeDups() { } stmts = append(stmts, stmt) } - f.Syntax.Stmt = stmts + syntax.Stmt = stmts } // lineLess returns whether li should be sorted before lj. It sorts diff --git a/libgo/go/golang.org/x/mod/modfile/work.go b/libgo/go/golang.org/x/mod/modfile/work.go new file mode 100644 index 00000000000..0c0e521525a --- /dev/null +++ b/libgo/go/golang.org/x/mod/modfile/work.go @@ -0,0 +1,234 @@ +// Copyright 2021 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 modfile + +import ( + "fmt" + "sort" + "strings" +) + +// A WorkFile is the parsed, interpreted form of a go.work file. +type WorkFile struct { + Go *Go + Use []*Use + Replace []*Replace + + Syntax *FileSyntax +} + +// A Use is a single directory statement. +type Use struct { + Path string // Use path of module. + ModulePath string // Module path in the comment. + Syntax *Line +} + +// ParseWork parses and returns a go.work file. +// +// file is the name of the file, used in positions and errors. +// +// data is the content of the file. +// +// fix is an optional function that canonicalizes module versions. +// If fix is nil, all module versions must be canonical (module.CanonicalVersion +// must return the same string). +func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) { + fs, err := parse(file, data) + if err != nil { + return nil, err + } + f := &WorkFile{ + Syntax: fs, + } + var errs ErrorList + + for _, x := range fs.Stmt { + switch x := x.(type) { + case *Line: + f.add(&errs, x, x.Token[0], x.Token[1:], fix) + + case *LineBlock: + if len(x.Token) > 1 { + errs = append(errs, Error{ + Filename: file, + Pos: x.Start, + Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")), + }) + continue + } + switch x.Token[0] { + default: + errs = append(errs, Error{ + Filename: file, + Pos: x.Start, + Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")), + }) + continue + case "use", "replace": + for _, l := range x.Line { + f.add(&errs, l, x.Token[0], l.Token, fix) + } + } + } + } + + if len(errs) > 0 { + return nil, errs + } + return f, nil +} + +// Cleanup cleans up the file f after any edit operations. +// To avoid quadratic behavior, modifications like DropRequire +// clear the entry but do not remove it from the slice. +// Cleanup cleans out all the cleared entries. +func (f *WorkFile) Cleanup() { + w := 0 + for _, r := range f.Use { + if r.Path != "" { + f.Use[w] = r + w++ + } + } + f.Use = f.Use[:w] + + w = 0 + for _, r := range f.Replace { + if r.Old.Path != "" { + f.Replace[w] = r + w++ + } + } + f.Replace = f.Replace[:w] + + f.Syntax.Cleanup() +} + +func (f *WorkFile) AddGoStmt(version string) error { + if !GoVersionRE.MatchString(version) { + return fmt.Errorf("invalid language version string %q", version) + } + if f.Go == nil { + stmt := &Line{Token: []string{"go", version}} + f.Go = &Go{ + Version: version, + Syntax: stmt, + } + // Find the first non-comment-only block that's and add + // the go statement before it. That will keep file comments at the top. + i := 0 + for i = 0; i < len(f.Syntax.Stmt); i++ { + if _, ok := f.Syntax.Stmt[i].(*CommentBlock); !ok { + break + } + } + f.Syntax.Stmt = append(append(f.Syntax.Stmt[:i:i], stmt), f.Syntax.Stmt[i:]...) + } else { + f.Go.Version = version + f.Syntax.updateLine(f.Go.Syntax, "go", version) + } + return nil +} + +func (f *WorkFile) AddUse(diskPath, modulePath string) error { + need := true + for _, d := range f.Use { + if d.Path == diskPath { + if need { + d.ModulePath = modulePath + f.Syntax.updateLine(d.Syntax, "use", AutoQuote(diskPath)) + need = false + } else { + d.Syntax.markRemoved() + *d = Use{} + } + } + } + + if need { + f.AddNewUse(diskPath, modulePath) + } + return nil +} + +func (f *WorkFile) AddNewUse(diskPath, modulePath string) { + line := f.Syntax.addLine(nil, "use", AutoQuote(diskPath)) + f.Use = append(f.Use, &Use{Path: diskPath, ModulePath: modulePath, Syntax: line}) +} + +func (f *WorkFile) SetUse(dirs []*Use) { + need := make(map[string]string) + for _, d := range dirs { + need[d.Path] = d.ModulePath + } + + for _, d := range f.Use { + if modulePath, ok := need[d.Path]; ok { + d.ModulePath = modulePath + } else { + d.Syntax.markRemoved() + *d = Use{} + } + } + + // TODO(#45713): Add module path to comment. + + for diskPath, modulePath := range need { + f.AddNewUse(diskPath, modulePath) + } + f.SortBlocks() +} + +func (f *WorkFile) DropUse(path string) error { + for _, d := range f.Use { + if d.Path == path { + d.Syntax.markRemoved() + *d = Use{} + } + } + return nil +} + +func (f *WorkFile) AddReplace(oldPath, oldVers, newPath, newVers string) error { + return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers) +} + +func (f *WorkFile) DropReplace(oldPath, oldVers string) error { + for _, r := range f.Replace { + if r.Old.Path == oldPath && r.Old.Version == oldVers { + r.Syntax.markRemoved() + *r = Replace{} + } + } + return nil +} + +func (f *WorkFile) SortBlocks() { + f.removeDups() // otherwise sorting is unsafe + + for _, stmt := range f.Syntax.Stmt { + block, ok := stmt.(*LineBlock) + if !ok { + continue + } + sort.SliceStable(block.Line, func(i, j int) bool { + return lineLess(block.Line[i], block.Line[j]) + }) + } +} + +// removeDups removes duplicate replace directives. +// +// Later replace directives take priority. +// +// require directives are not de-duplicated. That's left up to higher-level +// logic (MVS). +// +// retract directives are not de-duplicated since comments are +// meaningful, and versions may be retracted multiple times. +func (f *WorkFile) removeDups() { + removeDups(f.Syntax, nil, &f.Replace) +} diff --git a/libgo/go/golang.org/x/mod/module/module.go b/libgo/go/golang.org/x/mod/module/module.go index ba97ac356e9..355b5a45685 100644 --- a/libgo/go/golang.org/x/mod/module/module.go +++ b/libgo/go/golang.org/x/mod/module/module.go @@ -286,12 +286,7 @@ func fileNameOK(r rune) bool { if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' { return true } - for i := 0; i < len(allowed); i++ { - if rune(allowed[i]) == r { - return true - } - } - return false + return strings.ContainsRune(allowed, r) } // It may be OK to add more ASCII punctuation here, but only carefully. // For example Windows disallows < > \, and macOS disallows :, so we must not allow those. @@ -803,6 +798,7 @@ func unescapeString(escaped string) (string, bool) { // GOPRIVATE environment variable, as described by 'go help module-private'. // // It ignores any empty or malformed patterns in the list. +// Trailing slashes on patterns are ignored. func MatchPrefixPatterns(globs, target string) bool { for globs != "" { // Extract next non-empty glob in comma-separated list. @@ -812,6 +808,7 @@ func MatchPrefixPatterns(globs, target string) bool { } else { glob, globs = globs, "" } + glob = strings.TrimSuffix(glob, "/") if glob == "" { continue } diff --git a/libgo/go/golang.org/x/mod/semver/semver.go b/libgo/go/golang.org/x/mod/semver/semver.go index 7be398f80d3..a30a22bf20f 100644 --- a/libgo/go/golang.org/x/mod/semver/semver.go +++ b/libgo/go/golang.org/x/mod/semver/semver.go @@ -32,7 +32,6 @@ type parsed struct { short string prerelease string build string - err string } // IsValid reports whether v is a valid semantic version string. @@ -172,12 +171,10 @@ func Sort(list []string) { func parse(v string) (p parsed, ok bool) { if v == "" || v[0] != 'v' { - p.err = "missing v prefix" return } p.major, v, ok = parseInt(v[1:]) if !ok { - p.err = "bad major version" return } if v == "" { @@ -187,13 +184,11 @@ func parse(v string) (p parsed, ok bool) { return } if v[0] != '.' { - p.err = "bad minor prefix" ok = false return } p.minor, v, ok = parseInt(v[1:]) if !ok { - p.err = "bad minor version" return } if v == "" { @@ -202,31 +197,26 @@ func parse(v string) (p parsed, ok bool) { return } if v[0] != '.' { - p.err = "bad patch prefix" ok = false return } p.patch, v, ok = parseInt(v[1:]) if !ok { - p.err = "bad patch version" return } if len(v) > 0 && v[0] == '-' { p.prerelease, v, ok = parsePrerelease(v) if !ok { - p.err = "bad prerelease" return } } if len(v) > 0 && v[0] == '+' { p.build, v, ok = parseBuild(v) if !ok { - p.err = "bad build" return } } if v != "" { - p.err = "junk on end" ok = false return } diff --git a/libgo/go/golang.org/x/mod/zip/zip.go b/libgo/go/golang.org/x/mod/zip/zip.go index 5b401ad4d8f..ca0f7ad42f1 100644 --- a/libgo/go/golang.org/x/mod/zip/zip.go +++ b/libgo/go/golang.org/x/mod/zip/zip.go @@ -53,6 +53,7 @@ import ( "io" "io/ioutil" "os" + "os/exec" "path" "path/filepath" "strings" @@ -192,8 +193,10 @@ func CheckFiles(files []File) (CheckedFiles, error) { } // checkFiles implements CheckFiles and also returns lists of valid files and -// their sizes, corresponding to cf.Valid. These lists are used in Crewate to -// avoid repeated calls to File.Lstat. +// their sizes, corresponding to cf.Valid. It omits files in submodules, files +// in vendored packages, symlinked files, and various other unwanted files. +// +// The lists returned are used in Create to avoid repeated calls to File.Lstat. func checkFiles(files []File) (cf CheckedFiles, validFiles []File, validSizes []int64) { errPaths := make(map[string]struct{}) addError := func(path string, omitted bool, err error) { @@ -254,10 +257,12 @@ func checkFiles(files []File) (cf CheckedFiles, validFiles []File, validSizes [] continue } if isVendoredPackage(p) { + // Skip files in vendored packages. addError(p, true, errVendored) continue } if inSubmodule(p) { + // Skip submodule files. addError(p, true, errSubmoduleFile) continue } @@ -551,7 +556,7 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) { if zerr, ok := err.(*zipError); ok { zerr.path = dir } else if err != nil { - err = &zipError{verb: "create zip", path: dir, err: err} + err = &zipError{verb: "create zip from directory", path: dir, err: err} } }() @@ -563,6 +568,129 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) { return Create(w, m, files) } +// CreateFromVCS creates a module zip file for module m from the contents of a +// VCS repository stored locally. The zip content is written to w. +// +// repoRoot must be an absolute path to the base of the repository, such as +// "/Users/some-user/some-repo". +// +// revision is the revision of the repository to create the zip from. Examples +// include HEAD or SHA sums for git repositories. +// +// subdir must be the relative path from the base of the repository, such as +// "sub/dir". To create a zip from the base of the repository, pass an empty +// string. +// +// If CreateFromVCS returns ErrUnrecognizedVCS, consider falling back to +// CreateFromDir. +func CreateFromVCS(w io.Writer, m module.Version, repoRoot, revision, subdir string) (err error) { + defer func() { + if zerr, ok := err.(*zipError); ok { + zerr.path = repoRoot + } else if err != nil { + err = &zipError{verb: "create zip from version control system", path: repoRoot, err: err} + } + }() + + var filesToCreate []File + + switch { + case isGitRepo(repoRoot): + files, err := filesInGitRepo(repoRoot, revision, subdir) + if err != nil { + return err + } + + filesToCreate = files + default: + return &UnrecognizedVCSError{RepoRoot: repoRoot} + } + + return Create(w, m, filesToCreate) +} + +// UnrecognizedVCSError indicates that no recognized version control system was +// found in the given directory. +type UnrecognizedVCSError struct { + RepoRoot string +} + +func (e *UnrecognizedVCSError) Error() string { + return fmt.Sprintf("could not find a recognized version control system at %q", e.RepoRoot) +} + +// filterGitIgnored filters out any files that are git ignored in the directory. +func filesInGitRepo(dir, rev, subdir string) ([]File, error) { + stderr := bytes.Buffer{} + stdout := bytes.Buffer{} + + // Incredibly, git produces different archives depending on whether + // it is running on a Windows system or not, in an attempt to normalize + // text file line endings. Setting -c core.autocrlf=input means only + // translate files on the way into the repo, not on the way out (archive). + // The -c core.eol=lf should be unnecessary but set it anyway. + // + // Note: We use git archive to understand which files are actually included, + // ignoring things like .gitignore'd files. We could also use other + // techniques like git ls-files, but this approach most closely matches what + // the Go command does, which is beneficial. + // + // Note: some of this code copied from https://go.googlesource.com/go/+/refs/tags/go1.16.5/src/cmd/go/internal/modfetch/codehost/git.go#826. + cmd := exec.Command("git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", rev) + if subdir != "" { + cmd.Args = append(cmd.Args, subdir) + } + cmd.Dir = dir + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("error running `git archive`: %w, %s", err, stderr.String()) + } + + rawReader := bytes.NewReader(stdout.Bytes()) + zipReader, err := zip.NewReader(rawReader, int64(stdout.Len())) + if err != nil { + return nil, err + } + + var fs []File + for _, zf := range zipReader.File { + if !strings.HasPrefix(zf.Name, subdir) || strings.HasSuffix(zf.Name, "/") { + continue + } + + n := strings.TrimPrefix(zf.Name, subdir) + if n == "" { + continue + } + n = strings.TrimPrefix(n, string(filepath.Separator)) + + fs = append(fs, zipFile{ + name: n, + f: zf, + }) + } + + return fs, nil +} + +// isGitRepo reports whether the given directory is a git repo. +func isGitRepo(dir string) bool { + stdout := &bytes.Buffer{} + cmd := exec.Command("git", "rev-parse", "--git-dir") + cmd.Dir = dir + cmd.Stdout = stdout + if err := cmd.Run(); err != nil { + return false + } + gitDir := strings.TrimSpace(string(stdout.Bytes())) + if !filepath.IsAbs(gitDir) { + gitDir = filepath.Join(dir, gitDir) + } + wantDir := filepath.Join(dir, ".git") + return wantDir == gitDir +} + type dirFile struct { filePath, slashPath string info os.FileInfo @@ -572,6 +700,15 @@ func (f dirFile) Path() string { return f.slashPath } func (f dirFile) Lstat() (os.FileInfo, error) { return f.info, nil } func (f dirFile) Open() (io.ReadCloser, error) { return os.Open(f.filePath) } +type zipFile struct { + name string + f *zip.File +} + +func (f zipFile) Path() string { return f.name } +func (f zipFile) Lstat() (os.FileInfo, error) { return f.f.FileInfo(), nil } +func (f zipFile) Open() (io.ReadCloser, error) { return f.f.Open() } + // isVendoredPackage attempts to report whether the given filename is contained // in a package whose import path contains (but does not end with) the component // "vendor". diff --git a/libgo/go/golang.org/x/net/dns/dnsmessage/message.go b/libgo/go/golang.org/x/net/dns/dnsmessage/message.go index 1736fc5d12e..8c24430c5ce 100644 --- a/libgo/go/golang.org/x/net/dns/dnsmessage/message.go +++ b/libgo/go/golang.org/x/net/dns/dnsmessage/message.go @@ -125,14 +125,14 @@ func (o OpCode) GoString() string { // An RCode is a DNS response status code. type RCode uint16 +// Header.RCode values. const ( - // Message.Rcode - RCodeSuccess RCode = 0 - RCodeFormatError RCode = 1 - RCodeServerFailure RCode = 2 - RCodeNameError RCode = 3 - RCodeNotImplemented RCode = 4 - RCodeRefused RCode = 5 + RCodeSuccess RCode = 0 // NoError + RCodeFormatError RCode = 1 // FormErr + RCodeServerFailure RCode = 2 // ServFail + RCodeNameError RCode = 3 // NXDomain + RCodeNotImplemented RCode = 4 // NotImp + RCodeRefused RCode = 5 // Refused ) var rCodeNames = map[RCode]string{ @@ -1207,8 +1207,8 @@ type Builder struct { // // The DNS message is appended to the provided initial buffer buf (which may be // nil) as it is built. The final message is returned by the (*Builder).Finish -// method, which may return the same underlying array if there was sufficient -// capacity in the slice. +// method, which includes buf[:len(buf)] and may return the same underlying +// array if there was sufficient capacity in the slice. func NewBuilder(buf []byte, h Header) Builder { if buf == nil { buf = make([]byte, 0, packStartingCap) @@ -1713,7 +1713,7 @@ const ( // SetEDNS0 configures h for EDNS(0). // -// The provided extRCode must be an extedned RCode. +// The provided extRCode must be an extended RCode. func (h *ResourceHeader) SetEDNS0(udpPayloadLen int, extRCode RCode, dnssecOK bool) error { h.Name = Name{Data: [nameLen]byte{'.'}, Length: 1} // RFC 6891 section 6.1.2 h.Type = TypeOPT @@ -1880,7 +1880,7 @@ const nameLen = 255 // A Name is a non-encoded domain name. It is used instead of strings to avoid // allocations. type Name struct { - Data [nameLen]byte + Data [nameLen]byte // 255 bytes Length uint8 } diff --git a/libgo/go/golang.org/x/net/http/httpproxy/proxy.go b/libgo/go/golang.org/x/net/http/httpproxy/proxy.go index 1415b077912..d2c8c87eab9 100644 --- a/libgo/go/golang.org/x/net/http/httpproxy/proxy.go +++ b/libgo/go/golang.org/x/net/http/httpproxy/proxy.go @@ -113,8 +113,8 @@ func getEnvAny(names ...string) string { // environment, or a proxy should not be used for the given request, as // defined by NO_PROXY. // -// As a special case, if req.URL.Host is "localhost" (with or without a -// port number), then a nil URL and nil error will be returned. +// As a special case, if req.URL.Host is "localhost" or a loopback address +// (with or without a port number), then a nil URL and nil error will be returned. func (cfg *Config) ProxyFunc() func(reqURL *url.URL) (*url.URL, error) { // Preprocess the Config settings for more efficient evaluation. cfg1 := &config{ diff --git a/libgo/go/golang.org/x/net/http2/hpack/huffman.go b/libgo/go/golang.org/x/net/http2/hpack/huffman.go index a1ab2f05679..fe0b84ccd46 100644 --- a/libgo/go/golang.org/x/net/http2/hpack/huffman.go +++ b/libgo/go/golang.org/x/net/http2/hpack/huffman.go @@ -140,25 +140,29 @@ func buildRootHuffmanNode() { panic("unexpected size") } lazyRootHuffmanNode = newInternalNode() - for i, code := range huffmanCodes { - addDecoderNode(byte(i), code, huffmanCodeLen[i]) - } -} + // allocate a leaf node for each of the 256 symbols + leaves := new([256]node) + + for sym, code := range huffmanCodes { + codeLen := huffmanCodeLen[sym] + + cur := lazyRootHuffmanNode + for codeLen > 8 { + codeLen -= 8 + i := uint8(code >> codeLen) + if cur.children[i] == nil { + cur.children[i] = newInternalNode() + } + cur = cur.children[i] + } + shift := 8 - codeLen + start, end := int(uint8(code<<shift)), int(1<<shift) -func addDecoderNode(sym byte, code uint32, codeLen uint8) { - cur := lazyRootHuffmanNode - for codeLen > 8 { - codeLen -= 8 - i := uint8(code >> codeLen) - if cur.children[i] == nil { - cur.children[i] = newInternalNode() + leaves[sym].sym = byte(sym) + leaves[sym].codeLen = codeLen + for i := start; i < start+end; i++ { + cur.children[i] = &leaves[sym] } - cur = cur.children[i] - } - shift := 8 - codeLen - start, end := int(uint8(code<<shift)), int(1<<shift) - for i := start; i < start+end; i++ { - cur.children[i] = &node{sym: sym, codeLen: codeLen} } } diff --git a/libgo/go/golang.org/x/net/idna/go118.go b/libgo/go/golang.org/x/net/idna/go118.go new file mode 100644 index 00000000000..c5c4338dbed --- /dev/null +++ b/libgo/go/golang.org/x/net/idna/go118.go @@ -0,0 +1,14 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2021 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. + +//go:build go1.18 +// +build go1.18 + +package idna + +// Transitional processing is disabled by default in Go 1.18. +// https://golang.org/issue/47510 +const transitionalLookup = false diff --git a/libgo/go/golang.org/x/net/idna/idna10.0.0.go b/libgo/go/golang.org/x/net/idna/idna10.0.0.go index 5208ba6cb88..64ccf85febb 100644 --- a/libgo/go/golang.org/x/net/idna/idna10.0.0.go +++ b/libgo/go/golang.org/x/net/idna/idna10.0.0.go @@ -59,10 +59,10 @@ type Option func(*options) // Transitional sets a Profile to use the Transitional mapping as defined in UTS // #46. This will cause, for example, "Γ" to be mapped to "ss". Using the // transitional mapping provides a compromise between IDNA2003 and IDNA2008 -// compatibility. It is used by most browsers when resolving domain names. This +// compatibility. It is used by some browsers when resolving domain names. This // option is only meaningful if combined with MapForLookup. func Transitional(transitional bool) Option { - return func(o *options) { o.transitional = true } + return func(o *options) { o.transitional = transitional } } // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts @@ -284,7 +284,7 @@ var ( punycode = &Profile{} lookup = &Profile{options{ - transitional: true, + transitional: transitionalLookup, useSTD3Rules: true, checkHyphens: true, checkJoiners: true, diff --git a/libgo/go/golang.org/x/net/idna/idna9.0.0.go b/libgo/go/golang.org/x/net/idna/idna9.0.0.go index 55f718f1274..aae6aac872b 100644 --- a/libgo/go/golang.org/x/net/idna/idna9.0.0.go +++ b/libgo/go/golang.org/x/net/idna/idna9.0.0.go @@ -58,10 +58,10 @@ type Option func(*options) // Transitional sets a Profile to use the Transitional mapping as defined in UTS // #46. This will cause, for example, "Γ" to be mapped to "ss". Using the // transitional mapping provides a compromise between IDNA2003 and IDNA2008 -// compatibility. It is used by most browsers when resolving domain names. This +// compatibility. It is used by some browsers when resolving domain names. This // option is only meaningful if combined with MapForLookup. func Transitional(transitional bool) Option { - return func(o *options) { o.transitional = true } + return func(o *options) { o.transitional = transitional } } // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts diff --git a/libgo/go/golang.org/x/net/idna/pre_go118.go b/libgo/go/golang.org/x/net/idna/pre_go118.go new file mode 100644 index 00000000000..3aaccab1c5a --- /dev/null +++ b/libgo/go/golang.org/x/net/idna/pre_go118.go @@ -0,0 +1,12 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2021 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. + +//go:build !go1.18 +// +build !go1.18 + +package idna + +const transitionalLookup = true diff --git a/libgo/go/golang.org/x/net/idna/punycode.go b/libgo/go/golang.org/x/net/idna/punycode.go index 02c7d59af3b..e8e3ac11a94 100644 --- a/libgo/go/golang.org/x/net/idna/punycode.go +++ b/libgo/go/golang.org/x/net/idna/punycode.go @@ -49,6 +49,7 @@ func decode(encoded string) (string, error) { } } i, n, bias := int32(0), initialN, initialBias + overflow := false for pos < len(encoded) { oldI, w := i, int32(1) for k := base; ; k += base { @@ -60,29 +61,32 @@ func decode(encoded string) (string, error) { return "", punyError(encoded) } pos++ - i += digit * w - if i < 0 { + i, overflow = madd(i, digit, w) + if overflow { return "", punyError(encoded) } t := k - bias - if t < tmin { + if k <= bias { t = tmin - } else if t > tmax { + } else if k >= bias+tmax { t = tmax } if digit < t { break } - w *= base - t - if w >= math.MaxInt32/base { + w, overflow = madd(0, w, base-t) + if overflow { return "", punyError(encoded) } } + if len(output) >= 1024 { + return "", punyError(encoded) + } x := int32(len(output) + 1) bias = adapt(i-oldI, x, oldI == 0) n += i / x i %= x - if n > utf8.MaxRune || len(output) >= 1024 { + if n < 0 || n > utf8.MaxRune { return "", punyError(encoded) } output = append(output, 0) @@ -115,6 +119,7 @@ func encode(prefix, s string) (string, error) { if b > 0 { output = append(output, '-') } + overflow := false for remaining != 0 { m := int32(0x7fffffff) for _, r := range s { @@ -122,8 +127,8 @@ func encode(prefix, s string) (string, error) { m = r } } - delta += (m - n) * (h + 1) - if delta < 0 { + delta, overflow = madd(delta, m-n, h+1) + if overflow { return "", punyError(s) } n = m @@ -141,9 +146,9 @@ func encode(prefix, s string) (string, error) { q := delta for k := base; ; k += base { t := k - bias - if t < tmin { + if k <= bias { t = tmin - } else if t > tmax { + } else if k >= bias+tmax { t = tmax } if q < t { @@ -164,6 +169,15 @@ func encode(prefix, s string) (string, error) { return string(output), nil } +// madd computes a + (b * c), detecting overflow. +func madd(a, b, c int32) (next int32, overflow bool) { + p := int64(b) * int64(c) + if p > math.MaxInt32-int64(a) { + return 0, true + } + return a + int32(p), false +} + func decodeDigit(x byte) (digit int32, ok bool) { switch { case '0' <= x && x <= '9': diff --git a/libgo/go/golang.org/x/net/lif/address.go b/libgo/go/golang.org/x/net/lif/address.go index afb957fd8e1..34b6432d6e2 100644 --- a/libgo/go/golang.org/x/net/lif/address.go +++ b/libgo/go/golang.org/x/net/lif/address.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build solaris // +build solaris package lif diff --git a/libgo/go/golang.org/x/net/lif/binary.go b/libgo/go/golang.org/x/net/lif/binary.go index 738a94f4224..f31ca3ad072 100644 --- a/libgo/go/golang.org/x/net/lif/binary.go +++ b/libgo/go/golang.org/x/net/lif/binary.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build solaris // +build solaris package lif diff --git a/libgo/go/golang.org/x/net/lif/lif.go b/libgo/go/golang.org/x/net/lif/lif.go index 6e81f81f1c2..95c7d258466 100644 --- a/libgo/go/golang.org/x/net/lif/lif.go +++ b/libgo/go/golang.org/x/net/lif/lif.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build solaris // +build solaris // Package lif provides basic functions for the manipulation of diff --git a/libgo/go/golang.org/x/net/lif/link.go b/libgo/go/golang.org/x/net/lif/link.go index 913a53e1185..f1af1306ca3 100644 --- a/libgo/go/golang.org/x/net/lif/link.go +++ b/libgo/go/golang.org/x/net/lif/link.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build solaris // +build solaris package lif diff --git a/libgo/go/golang.org/x/net/lif/sys.go b/libgo/go/golang.org/x/net/lif/sys.go index c896041b7b4..d0b532d9dc9 100644 --- a/libgo/go/golang.org/x/net/lif/sys.go +++ b/libgo/go/golang.org/x/net/lif/sys.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build solaris // +build solaris package lif diff --git a/libgo/go/golang.org/x/net/lif/syscall.go b/libgo/go/golang.org/x/net/lif/syscall.go index ea7541456bd..d2e9e619547 100644 --- a/libgo/go/golang.org/x/net/lif/syscall.go +++ b/libgo/go/golang.org/x/net/lif/syscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build solaris // +build solaris package lif diff --git a/libgo/go/golang.org/x/net/nettest/nettest.go b/libgo/go/golang.org/x/net/nettest/nettest.go index 83ba858e249..ae5413b23df 100644 --- a/libgo/go/golang.org/x/net/nettest/nettest.go +++ b/libgo/go/golang.org/x/net/nettest/nettest.go @@ -95,13 +95,8 @@ func TestableNetwork(network string) bool { // This is an internal network name for testing on the // package net of the standard library. switch runtime.GOOS { - case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows": + case "android", "fuchsia", "hurd", "ios", "js", "nacl", "plan9", "windows": return false - case "darwin", "ios": - // iOS doesn't support it. - if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { - return false - } } case "ip", "ip4", "ip6": switch runtime.GOOS { @@ -114,15 +109,10 @@ func TestableNetwork(network string) bool { } case "unix", "unixgram": switch runtime.GOOS { - case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows": + case "android", "fuchsia", "hurd", "ios", "js", "nacl", "plan9", "windows": return false case "aix": return unixStrmDgramEnabled() - case "darwin", "ios": - // iOS does not support unix, unixgram. - if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { - return false - } } case "unixpacket": switch runtime.GOOS { diff --git a/libgo/go/golang.org/x/net/route/address.go b/libgo/go/golang.org/x/net/route/address.go index 4f6ad968a24..1898ed0fad5 100644 --- a/libgo/go/golang.org/x/net/route/address.go +++ b/libgo/go/golang.org/x/net/route/address.go @@ -422,5 +422,9 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ( b = b[l:] } } + // The only remaining bytes in b should be alignment. + // However, under some circumstances DragonFly BSD appears to put + // more addresses in the message than are indicated in the address + // bitmask, so don't check for this. return as[:], nil } diff --git a/libgo/go/golang.org/x/net/route/message.go b/libgo/go/golang.org/x/net/route/message.go index d53bb7f9b13..456a8363fec 100644 --- a/libgo/go/golang.org/x/net/route/message.go +++ b/libgo/go/golang.org/x/net/route/message.go @@ -53,7 +53,7 @@ func ParseRIB(typ RIBType, b []byte) ([]Message, error) { if w, ok := wireFormats[int(b[3])]; !ok { nskips++ } else { - m, err := w.parse(typ, b) + m, err := w.parse(typ, b[:l]) if err != nil { return nil, err } diff --git a/libgo/go/golang.org/x/net/route/sys_freebsd.go b/libgo/go/golang.org/x/net/route/sys_freebsd.go index fe91be1249c..3599601740c 100644 --- a/libgo/go/golang.org/x/net/route/sys_freebsd.go +++ b/libgo/go/golang.org/x/net/route/sys_freebsd.go @@ -134,9 +134,6 @@ func probeRoutingStack() (int, map[int]*wireFormat) { } else { ifm.bodyOff = sizeofIfMsghdrFreeBSD11 } - if rel >= 1102000 { // see https://github.com/freebsd/freebsd/commit/027c7f4d66ff8d8c4a46c3665a5ee7d6d8462034#diff-ad4e5b7f1449ea3fc87bc97280de145b - align = wordSize - } } rtm.parse = rtm.parseRouteMessage ifm.parse = ifm.parseInterfaceMessage diff --git a/libgo/go/golang.org/x/net/route/syscall.go b/libgo/go/golang.org/x/net/route/syscall.go index 97166dd3c4c..68d37c9621c 100644 --- a/libgo/go/golang.org/x/net/route/syscall.go +++ b/libgo/go/golang.org/x/net/route/syscall.go @@ -2,28 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || freebsd || netbsd || openbsd -// +build dragonfly freebsd netbsd openbsd +//go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd package route -import ( - "syscall" - "unsafe" -) +import _ "unsafe" // for linkname -var zero uintptr - -func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { - var p unsafe.Pointer - if len(mib) > 0 { - p = unsafe.Pointer(&mib[0]) - } else { - p = unsafe.Pointer(&zero) - } - _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), newlen) - if errno != 0 { - return error(errno) - } - return nil -} +//go:linkname sysctl syscall.sysctl +func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error diff --git a/libgo/go/golang.org/x/sync/AUTHORS b/libgo/go/golang.org/x/sync/AUTHORS new file mode 100644 index 00000000000..15167cd746c --- /dev/null +++ b/libgo/go/golang.org/x/sync/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/libgo/go/golang.org/x/sync/CONTRIBUTORS b/libgo/go/golang.org/x/sync/CONTRIBUTORS new file mode 100644 index 00000000000..1c4577e9680 --- /dev/null +++ b/libgo/go/golang.org/x/sync/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/libgo/go/golang.org/x/sync/LICENSE b/libgo/go/golang.org/x/sync/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/libgo/go/golang.org/x/sync/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libgo/go/golang.org/x/sync/PATENTS b/libgo/go/golang.org/x/sync/PATENTS new file mode 100644 index 00000000000..733099041f8 --- /dev/null +++ b/libgo/go/golang.org/x/sync/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/libgo/go/golang.org/x/sync/semaphore/semaphore.go b/libgo/go/golang.org/x/sync/semaphore/semaphore.go new file mode 100644 index 00000000000..30f632c577b --- /dev/null +++ b/libgo/go/golang.org/x/sync/semaphore/semaphore.go @@ -0,0 +1,136 @@ +// Copyright 2017 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 semaphore provides a weighted semaphore implementation. +package semaphore // import "golang.org/x/sync/semaphore" + +import ( + "container/list" + "context" + "sync" +) + +type waiter struct { + n int64 + ready chan<- struct{} // Closed when semaphore acquired. +} + +// NewWeighted creates a new weighted semaphore with the given +// maximum combined weight for concurrent access. +func NewWeighted(n int64) *Weighted { + w := &Weighted{size: n} + return w +} + +// Weighted provides a way to bound concurrent access to a resource. +// The callers can request access with a given weight. +type Weighted struct { + size int64 + cur int64 + mu sync.Mutex + waiters list.List +} + +// Acquire acquires the semaphore with a weight of n, blocking until resources +// are available or ctx is done. On success, returns nil. On failure, returns +// ctx.Err() and leaves the semaphore unchanged. +// +// If ctx is already done, Acquire may still succeed without blocking. +func (s *Weighted) Acquire(ctx context.Context, n int64) error { + s.mu.Lock() + if s.size-s.cur >= n && s.waiters.Len() == 0 { + s.cur += n + s.mu.Unlock() + return nil + } + + if n > s.size { + // Don't make other Acquire calls block on one that's doomed to fail. + s.mu.Unlock() + <-ctx.Done() + return ctx.Err() + } + + ready := make(chan struct{}) + w := waiter{n: n, ready: ready} + elem := s.waiters.PushBack(w) + s.mu.Unlock() + + select { + case <-ctx.Done(): + err := ctx.Err() + s.mu.Lock() + select { + case <-ready: + // Acquired the semaphore after we were canceled. Rather than trying to + // fix up the queue, just pretend we didn't notice the cancelation. + err = nil + default: + isFront := s.waiters.Front() == elem + s.waiters.Remove(elem) + // If we're at the front and there're extra tokens left, notify other waiters. + if isFront && s.size > s.cur { + s.notifyWaiters() + } + } + s.mu.Unlock() + return err + + case <-ready: + return nil + } +} + +// TryAcquire acquires the semaphore with a weight of n without blocking. +// On success, returns true. On failure, returns false and leaves the semaphore unchanged. +func (s *Weighted) TryAcquire(n int64) bool { + s.mu.Lock() + success := s.size-s.cur >= n && s.waiters.Len() == 0 + if success { + s.cur += n + } + s.mu.Unlock() + return success +} + +// Release releases the semaphore with a weight of n. +func (s *Weighted) Release(n int64) { + s.mu.Lock() + s.cur -= n + if s.cur < 0 { + s.mu.Unlock() + panic("semaphore: released more than held") + } + s.notifyWaiters() + s.mu.Unlock() +} + +func (s *Weighted) notifyWaiters() { + for { + next := s.waiters.Front() + if next == nil { + break // No more waiters blocked. + } + + w := next.Value.(waiter) + if s.size-s.cur < w.n { + // Not enough tokens for the next waiter. We could keep going (to try to + // find a waiter with a smaller request), but under load that could cause + // starvation for large requests; instead, we leave all remaining waiters + // blocked. + // + // Consider a semaphore used as a read-write lock, with N tokens, N + // readers, and one writer. Each reader can Acquire(1) to obtain a read + // lock. The writer can Acquire(N) to obtain a write lock, excluding all + // of the readers. If we allow the readers to jump ahead in the queue, + // the writer will starve β there is always one token available for every + // reader. + break + } + + s.cur += w.n + s.waiters.Remove(next) + close(w.ready) + } +} diff --git a/libgo/go/golang.org/x/sys/cpu/cpu.go b/libgo/go/golang.org/x/sys/cpu/cpu.go index abbec2d44bf..b56886f2616 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu.go @@ -56,6 +56,7 @@ var X86 struct { HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions HasBMI1 bool // Bit manipulation instruction set 1 HasBMI2 bool // Bit manipulation instruction set 2 + HasCX16 bool // Compare and exchange 16 Bytes HasERMS bool // Enhanced REP for MOVSB and STOSB HasFMA bool // Fused-multiply-add instructions HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_gc_x86.go b/libgo/go/golang.org/x/sys/cpu/cpu_gc_x86.go index 3298a87e981..fa7cdb9bcd5 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_gc_x86.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -15,7 +15,3 @@ func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) // xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler // and in cpu_gccgo.c for gccgo. func xgetbv() (eax, edx uint32) - -// darwinSupportsAVX512 is implemented in cpu_x86.s for gc compiler -// and in cpu_gccgo_x86.go for gccgo. -func darwinSupportsAVX512() bool diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_x86.go b/libgo/go/golang.org/x/sys/cpu/cpu_x86.go index e50ed987599..1a99e94fee0 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_x86.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_x86.go @@ -39,6 +39,7 @@ func initOptions() { {Name: "avx512bf16", Feature: &X86.HasAVX512BF16}, {Name: "bmi1", Feature: &X86.HasBMI1}, {Name: "bmi2", Feature: &X86.HasBMI2}, + {Name: "cx16", Feature: &X86.HasCX16}, {Name: "erms", Feature: &X86.HasERMS}, {Name: "fma", Feature: &X86.HasFMA}, {Name: "osxsave", Feature: &X86.HasOSXSAVE}, @@ -73,6 +74,7 @@ func archInit() { X86.HasPCLMULQDQ = isSet(1, ecx1) X86.HasSSSE3 = isSet(9, ecx1) X86.HasFMA = isSet(12, ecx1) + X86.HasCX16 = isSet(13, ecx1) X86.HasSSE41 = isSet(19, ecx1) X86.HasSSE42 = isSet(20, ecx1) X86.HasPOPCNT = isSet(23, ecx1) @@ -88,9 +90,10 @@ func archInit() { osSupportsAVX = isSet(1, eax) && isSet(2, eax) if runtime.GOOS == "darwin" { - // Check darwin commpage for AVX512 support. Necessary because: - // https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/osfmk/i386/fpu.c#L175-L201 - osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512() + // Darwin doesn't save/restore AVX-512 mask registers correctly across signal handlers. + // Since users can't rely on mask register contents, let's not advertise AVX-512 support. + // See issue 49233. + osSupportsAVX512 = false } else { // Check if OPMASK and ZMM registers have OS support. osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) diff --git a/libgo/go/golang.org/x/text/unicode/bidi/core.go b/libgo/go/golang.org/x/text/unicode/bidi/core.go index e4c0811016c..fde188a33b0 100644 --- a/libgo/go/golang.org/x/text/unicode/bidi/core.go +++ b/libgo/go/golang.org/x/text/unicode/bidi/core.go @@ -495,9 +495,9 @@ func (s *isolatingRunSequence) resolveWeakTypes() { if t == NSM { s.types[i] = precedingCharacterType } else { - if t.in(LRI, RLI, FSI, PDI) { - precedingCharacterType = ON - } + // if t.in(LRI, RLI, FSI, PDI) { + // precedingCharacterType = ON + // } precedingCharacterType = t } } diff --git a/libgo/go/golang.org/x/tools/cover/profile.go b/libgo/go/golang.org/x/tools/cover/profile.go index 57195774cea..47a9a541164 100644 --- a/libgo/go/golang.org/x/tools/cover/profile.go +++ b/libgo/go/golang.org/x/tools/cover/profile.go @@ -10,6 +10,7 @@ import ( "bufio" "errors" "fmt" + "io" "math" "os" "sort" @@ -45,14 +46,18 @@ func ParseProfiles(fileName string) ([]*Profile, error) { return nil, err } defer pf.Close() + return ParseProfilesFromReader(pf) +} - files := make(map[string]*Profile) - buf := bufio.NewReader(pf) +// ParseProfilesFromReader parses profile data from the Reader and +// returns a Profile for each source file described therein. +func ParseProfilesFromReader(rd io.Reader) ([]*Profile, error) { // First line is "mode: foo", where foo is "set", "count", or "atomic". // Rest of file is in the format // encoding/base64/base64.go:34.44,37.40 3 1 // where the fields are: name.go:line.column,line.column numberOfStatements count - s := bufio.NewScanner(buf) + files := make(map[string]*Profile) + s := bufio.NewScanner(rd) mode := "" for s.Scan() { line := s.Text() diff --git a/libgo/go/golang.org/x/tools/go/analysis/internal/facts/imports.go b/libgo/go/golang.org/x/tools/go/analysis/internal/facts/imports.go index 34740f48e04..ade0cc6fab4 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/internal/facts/imports.go +++ b/libgo/go/golang.org/x/tools/go/analysis/internal/facts/imports.go @@ -4,7 +4,11 @@ package facts -import "go/types" +import ( + "go/types" + + "golang.org/x/tools/internal/typeparams" +) // importMap computes the import map for a package by traversing the // entire exported API each of its imports. @@ -42,9 +46,20 @@ func importMap(imports []*types.Package) map[string]*types.Package { // nop case *types.Named: if addObj(T.Obj()) { + // TODO(taking): Investigate why the Underlying type is not added here. for i := 0; i < T.NumMethods(); i++ { addObj(T.Method(i)) } + if tparams := typeparams.ForNamed(T); tparams != nil { + for i := 0; i < tparams.Len(); i++ { + addType(tparams.At(i)) + } + } + if targs := typeparams.NamedTypeArgs(T); targs != nil { + for i := 0; i < targs.Len(); i++ { + addType(targs.At(i)) + } + } } case *types.Pointer: addType(T.Elem()) @@ -60,6 +75,11 @@ func importMap(imports []*types.Package) map[string]*types.Package { case *types.Signature: addType(T.Params()) addType(T.Results()) + if tparams := typeparams.ForSignature(T); tparams != nil { + for i := 0; i < tparams.Len(); i++ { + addType(tparams.At(i)) + } + } case *types.Struct: for i := 0; i < T.NumFields(); i++ { addObj(T.Field(i)) @@ -72,6 +92,17 @@ func importMap(imports []*types.Package) map[string]*types.Package { for i := 0; i < T.NumMethods(); i++ { addObj(T.Method(i)) } + for i := 0; i < T.NumEmbeddeds(); i++ { + addType(T.EmbeddedType(i)) // walk Embedded for implicits + } + case *typeparams.Union: + for i := 0; i < T.Len(); i++ { + addType(T.Term(i).Type()) + } + case *typeparams.TypeParam: + if addObj(T.Obj()) { + addType(T.Constraint()) + } } } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go index 34c7a36234d..3997ac861df 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go @@ -51,6 +51,11 @@ type asmArch struct { bigEndian bool stack string lr bool + // retRegs is a list of registers for return value in register ABI (ABIInternal). + // For now, as we only check whether we write to any result, here we only need to + // include the first integer register and first floating-point register. Accessing + // any of them counts as writing to result. + retRegs []string // calculated during initialization sizes types.Sizes intSize int @@ -79,8 +84,8 @@ type asmVar struct { var ( asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false} asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true} - asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true} - asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false} + asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true, retRegs: []string{"R0", "F0"}} + asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false, retRegs: []string{"AX", "X0"}} asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true} asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true} asmArchMips64 = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true} @@ -139,7 +144,7 @@ var ( asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`) asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`) ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`) - abiSuff = re(`^(.+)<ABI.+>$`) + abiSuff = re(`^(.+)<(ABI.+)>$`) ) func run(pass *analysis.Pass) (interface{}, error) { @@ -187,6 +192,7 @@ Files: var ( fn *asmFunc fnName string + abi string localSize, argSize int wroteSP bool noframe bool @@ -197,18 +203,22 @@ Files: flushRet := func() { if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 { v := fn.vars["ret"] + resultStr := fmt.Sprintf("%d-byte ret+%d(FP)", v.size, v.off) + if abi == "ABIInternal" { + resultStr = "result register" + } for _, line := range retLine { - pass.Reportf(analysisutil.LineStart(tf, line), "[%s] %s: RET without writing to %d-byte ret+%d(FP)", arch, fnName, v.size, v.off) + pass.Reportf(analysisutil.LineStart(tf, line), "[%s] %s: RET without writing to %s", arch, fnName, resultStr) } } retLine = nil } - trimABI := func(fnName string) string { + trimABI := func(fnName string) (string, string) { m := abiSuff.FindStringSubmatch(fnName) if m != nil { - return m[1] + return m[1], m[2] } - return fnName + return fnName, "" } for lineno, line := range lines { lineno++ @@ -275,11 +285,12 @@ Files: // log.Printf("%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", fname, lineno, arch, fnName, pkgPath) fn = nil fnName = "" + abi = "" continue } } // Trim off optional ABI selector. - fnName := trimABI(fnName) + fnName, abi = trimABI(fnName) flag := m[3] fn = knownFunc[fnName][arch] if fn != nil { @@ -307,6 +318,7 @@ Files: flushRet() fn = nil fnName = "" + abi = "" continue } @@ -337,6 +349,15 @@ Files: haveRetArg = true } + if abi == "ABIInternal" && !haveRetArg { + for _, reg := range archDef.retRegs { + if strings.Contains(line, reg) { + haveRetArg = true + break + } + } + } + for _, m := range asmSP.FindAllStringSubmatch(line, -1) { if m[3] != archDef.stack || wroteSP || noframe { continue diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go b/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go index 4c3ac6647f6..d3670aca97a 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/typeparams" ) const Doc = `check for unkeyed composite literals @@ -67,41 +68,61 @@ func run(pass *analysis.Pass) (interface{}, error) { // skip whitelisted types return } - under := typ.Underlying() - for { - ptr, ok := under.(*types.Pointer) - if !ok { - break + var structuralTypes []types.Type + switch typ := typ.(type) { + case *typeparams.TypeParam: + terms, err := typeparams.StructuralTerms(typ) + if err != nil { + return // invalid type } - under = ptr.Elem().Underlying() - } - if _, ok := under.(*types.Struct); !ok { - // skip non-struct composite literals - return - } - if isLocalType(pass, typ) { - // allow unkeyed locally defined composite literal - return + for _, term := range terms { + structuralTypes = append(structuralTypes, term.Type()) + } + default: + structuralTypes = append(structuralTypes, typ) } + for _, typ := range structuralTypes { + under := deref(typ.Underlying()) + if _, ok := under.(*types.Struct); !ok { + // skip non-struct composite literals + continue + } + if isLocalType(pass, typ) { + // allow unkeyed locally defined composite literal + continue + } - // check if the CompositeLit contains an unkeyed field - allKeyValue := true - for _, e := range cl.Elts { - if _, ok := e.(*ast.KeyValueExpr); !ok { - allKeyValue = false - break + // check if the CompositeLit contains an unkeyed field + allKeyValue := true + for _, e := range cl.Elts { + if _, ok := e.(*ast.KeyValueExpr); !ok { + allKeyValue = false + break + } } - } - if allKeyValue { - // all the composite literal fields are keyed + if allKeyValue { + // all the composite literal fields are keyed + continue + } + + pass.ReportRangef(cl, "%s composite literal uses unkeyed fields", typeName) return } - - pass.ReportRangef(cl, "%s composite literal uses unkeyed fields", typeName) }) return nil, nil } +func deref(typ types.Type) types.Type { + for { + ptr, ok := typ.(*types.Pointer) + if !ok { + break + } + typ = ptr.Elem().Underlying() + } + return typ +} + func isLocalType(pass *analysis.Pass, typ types.Type) bool { switch x := typ.(type) { case *types.Struct: @@ -112,6 +133,8 @@ func isLocalType(pass *analysis.Pass, typ types.Type) bool { case *types.Named: // names in package foo are local to foo_test too return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test") + case *typeparams.TypeParam: + return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test") } return false } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/copylock/copylock.go b/libgo/go/golang.org/x/tools/go/analysis/passes/copylock/copylock.go index c4ebf785710..350dc4e0fec 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/copylock/copylock.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/copylock/copylock.go @@ -17,6 +17,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/typeparams" ) const Doc = `check for locks erroneously passed by value @@ -145,7 +146,7 @@ func checkCopyLocksCallExpr(pass *analysis.Pass, ce *ast.CallExpr) { func checkCopyLocksFunc(pass *analysis.Pass, name string, recv *ast.FieldList, typ *ast.FuncType) { if recv != nil && len(recv.List) > 0 { expr := recv.List[0].Type - if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type); path != nil { + if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type, nil); path != nil { pass.ReportRangef(expr, "%s passes lock by value: %v", name, path) } } @@ -153,7 +154,7 @@ func checkCopyLocksFunc(pass *analysis.Pass, name string, recv *ast.FieldList, t if typ.Params != nil { for _, field := range typ.Params.List { expr := field.Type - if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type); path != nil { + if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type, nil); path != nil { pass.ReportRangef(expr, "%s passes lock by value: %v", name, path) } } @@ -199,12 +200,12 @@ func checkCopyLocksRangeVar(pass *analysis.Pass, rtok token.Token, e ast.Expr) { if typ == nil { return } - if path := lockPath(pass.Pkg, typ); path != nil { + if path := lockPath(pass.Pkg, typ, nil); path != nil { pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisutil.Format(pass.Fset, e), path) } } -type typePath []types.Type +type typePath []string // String pretty-prints a typePath. func (path typePath) String() string { @@ -215,7 +216,7 @@ func (path typePath) String() string { fmt.Fprint(&buf, " contains ") } // The human-readable path is in reverse order, outermost to innermost. - fmt.Fprint(&buf, path[n-i-1].String()) + fmt.Fprint(&buf, path[n-i-1]) } return buf.String() } @@ -234,16 +235,57 @@ func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath { return nil } } - return lockPath(pass.Pkg, pass.TypesInfo.Types[x].Type) + return lockPath(pass.Pkg, pass.TypesInfo.Types[x].Type, nil) } // lockPath returns a typePath describing the location of a lock value // contained in typ. If there is no contained lock, it returns nil. -func lockPath(tpkg *types.Package, typ types.Type) typePath { +// +// The seenTParams map is used to short-circuit infinite recursion via type +// parameters. +func lockPath(tpkg *types.Package, typ types.Type, seenTParams map[*typeparams.TypeParam]bool) typePath { if typ == nil { return nil } + if tpar, ok := typ.(*typeparams.TypeParam); ok { + if seenTParams == nil { + // Lazily allocate seenTParams, since the common case will not involve + // any type parameters. + seenTParams = make(map[*typeparams.TypeParam]bool) + } + if seenTParams[tpar] { + return nil + } + seenTParams[tpar] = true + terms, err := typeparams.StructuralTerms(tpar) + if err != nil { + return nil // invalid type + } + for _, term := range terms { + subpath := lockPath(tpkg, term.Type(), seenTParams) + if len(subpath) > 0 { + if term.Tilde() { + // Prepend a tilde to our lock path entry to clarify the resulting + // diagnostic message. Consider the following example: + // + // func _[Mutex interface{ ~sync.Mutex; M() }](m Mutex) {} + // + // Here the naive error message will be something like "passes lock + // by value: Mutex contains sync.Mutex". This is misleading because + // the local type parameter doesn't actually contain sync.Mutex, + // which lacks the M method. + // + // With tilde, it is clearer that the containment is via an + // approximation element. + subpath[len(subpath)-1] = "~" + subpath[len(subpath)-1] + } + return append(subpath, typ.String()) + } + } + return nil + } + for { atyp, ok := typ.Underlying().(*types.Array) if !ok { @@ -252,6 +294,17 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath { typ = atyp.Elem() } + ttyp, ok := typ.Underlying().(*types.Tuple) + if ok { + for i := 0; i < ttyp.Len(); i++ { + subpath := lockPath(tpkg, ttyp.At(i).Type(), seenTParams) + if subpath != nil { + return append(subpath, typ.String()) + } + } + return nil + } + // We're only interested in the case in which the underlying // type is a struct. (Interfaces and pointers are safe to copy.) styp, ok := typ.Underlying().(*types.Struct) @@ -263,7 +316,7 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath { // is a sync.Locker, but a value is not. This differentiates // embedded interfaces from embedded values. if types.Implements(types.NewPointer(typ), lockerType) && !types.Implements(typ, lockerType) { - return []types.Type{typ} + return []string{typ.String()} } // In go1.10, sync.noCopy did not implement Locker. @@ -272,15 +325,15 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath { if named, ok := typ.(*types.Named); ok && named.Obj().Name() == "noCopy" && named.Obj().Pkg().Path() == "sync" { - return []types.Type{typ} + return []string{typ.String()} } nfields := styp.NumFields() for i := 0; i < nfields; i++ { ftyp := styp.Field(i).Type() - subpath := lockPath(tpkg, ftyp) + subpath := lockPath(tpkg, ftyp, seenTParams) if subpath != nil { - return append(subpath, typ) + return append(subpath, typ.String()) } } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go b/libgo/go/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go index 51600ffc7eb..73746d6f04d 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go @@ -187,7 +187,11 @@ func (c *CFGs) callMayReturn(call *ast.CallExpr) (r bool) { return false // panic never returns } - // Is this a static call? + // Is this a static call? Also includes static functions + // parameterized by a type. Such functions may or may not + // return depending on the parameter type, but in some + // cases the answer is definite. We let ctrlflow figure + // that out. fn := typeutil.StaticCallee(c.pass.TypesInfo, call) if fn == nil { return true // callee not statically known; be conservative diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go b/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go index fd2285332cc..30130f63ea6 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go @@ -51,6 +51,12 @@ func assertableTo(v, t types.Type) *types.Func { if V == nil || T == nil { return nil } + + // Mitigations for interface comparisons and generics. + // TODO(https://github.com/golang/go/issues/50658): Support more precise conclusion. + if isParameterized(V) || isParameterized(T) { + return nil + } if f, wrongType := types.MissingMethod(V, T, false); wrongType { return f } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go b/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go new file mode 100644 index 00000000000..1285ecf1367 --- /dev/null +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go @@ -0,0 +1,112 @@ +// Copyright 2022 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 ifaceassert + +import ( + "go/types" + + "golang.org/x/tools/internal/typeparams" +) + +// isParameterized reports whether typ contains any of the type parameters of tparams. +// +// NOTE: Adapted from go/types/infer.go. If that is exported in a future release remove this copy. +func isParameterized(typ types.Type) bool { + w := tpWalker{ + seen: make(map[types.Type]bool), + } + return w.isParameterized(typ) +} + +type tpWalker struct { + seen map[types.Type]bool +} + +func (w *tpWalker) isParameterized(typ types.Type) (res bool) { + // detect cycles + if x, ok := w.seen[typ]; ok { + return x + } + w.seen[typ] = false + defer func() { + w.seen[typ] = res + }() + + switch t := typ.(type) { + case nil, *types.Basic: // TODO(gri) should nil be handled here? + break + + case *types.Array: + return w.isParameterized(t.Elem()) + + case *types.Slice: + return w.isParameterized(t.Elem()) + + case *types.Struct: + for i, n := 0, t.NumFields(); i < n; i++ { + if w.isParameterized(t.Field(i).Type()) { + return true + } + } + + case *types.Pointer: + return w.isParameterized(t.Elem()) + + case *types.Tuple: + n := t.Len() + for i := 0; i < n; i++ { + if w.isParameterized(t.At(i).Type()) { + return true + } + } + + case *types.Signature: + // t.tparams may not be nil if we are looking at a signature + // of a generic function type (or an interface method) that is + // part of the type we're testing. We don't care about these type + // parameters. + // Similarly, the receiver of a method may declare (rather then + // use) type parameters, we don't care about those either. + // Thus, we only need to look at the input and result parameters. + return w.isParameterized(t.Params()) || w.isParameterized(t.Results()) + + case *types.Interface: + for i, n := 0, t.NumMethods(); i < n; i++ { + if w.isParameterized(t.Method(i).Type()) { + return true + } + } + terms, err := typeparams.InterfaceTermSet(t) + if err != nil { + panic(err) + } + for _, term := range terms { + if w.isParameterized(term.Type()) { + return true + } + } + + case *types.Map: + return w.isParameterized(t.Key()) || w.isParameterized(t.Elem()) + + case *types.Chan: + return w.isParameterized(t.Elem()) + + case *types.Named: + list := typeparams.NamedTypeArgs(t) + for i, n := 0, list.Len(); i < n; i++ { + if w.isParameterized(list.At(i)) { + return true + } + } + + case *typeparams.TypeParam: + return true + + default: + panic(t) // unreachable + } + + return false +} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go b/libgo/go/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go index cd42c9897f2..e4c66df6d6d 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/typeparams" ) const Doc = `check for useless comparisons between functions and nil @@ -59,6 +60,12 @@ func run(pass *analysis.Pass) (interface{}, error) { obj = pass.TypesInfo.Uses[v] case *ast.SelectorExpr: obj = pass.TypesInfo.Uses[v.Sel] + case *ast.IndexExpr, *typeparams.IndexListExpr: + // Check generic functions such as "f[T1,T2]". + x, _, _, _ := typeparams.UnpackIndexExpr(v) + if id, ok := x.(*ast.Ident); ok { + obj = pass.TypesInfo.Uses[id] + } default: return } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go index 822820f06e9..dee37d78ae0 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -25,6 +25,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/typeparams" ) func init() { @@ -452,8 +453,15 @@ func stringConstantArg(pass *analysis.Pass, call *ast.CallExpr, idx int) (string if idx >= len(call.Args) { return "", false } - arg := call.Args[idx] - lit := pass.TypesInfo.Types[arg].Value + return stringConstantExpr(pass, call.Args[idx]) +} + +// stringConstantExpr returns expression's string constant value. +// +// ("", false) is returned if expression isn't a string +// constant. +func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool) { + lit := pass.TypesInfo.Types[expr].Value if lit != nil && lit.Kind() == constant.String { return constant.StringVal(lit), true } @@ -490,7 +498,7 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, _, ok = isPrint[strings.ToLower(fn.Name())] } if ok { - if fn.Name() == "Errorf" { + if fn.FullName() == "fmt.Errorf" { kind = KindErrorf } else if strings.HasSuffix(fn.Name(), "f") { kind = KindPrintf @@ -513,7 +521,12 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, func isFormatter(typ types.Type) bool { // If the type is an interface, the value it holds might satisfy fmt.Formatter. if _, ok := typ.Underlying().(*types.Interface); ok { - return true + // Don't assume type parameters could be formatters. With the greater + // expressiveness of constraint interface syntax we expect more type safety + // when using type parameters. + if !typeparams.IsTypeParam(typ) { + return true + } } obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format") fn, ok := obj.(*types.Func) @@ -555,7 +568,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F format, idx := formatString(pass, call) if idx < 0 { if false { - pass.Reportf(call.Lparen, "can't check non-constant format in call to %s", fn.Name()) + pass.Reportf(call.Lparen, "can't check non-constant format in call to %s", fn.FullName()) } return } @@ -563,7 +576,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F firstArg := idx + 1 // Arguments are immediately after format string. if !strings.Contains(format, "%") { if len(call.Args) > firstArg { - pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.Name()) + pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.FullName()) } return } @@ -577,7 +590,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F if format[i] != '%' { continue } - state := parsePrintfVerb(pass, call, fn.Name(), format[i:], firstArg, argNum) + state := parsePrintfVerb(pass, call, fn.FullName(), format[i:], firstArg, argNum) if state == nil { return } @@ -589,8 +602,9 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F anyIndex = true } if state.verb == 'w' { - if kind != KindErrorf { - pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w, which is only supported by Errorf", state.name) + switch kind { + case KindNone, KindPrint, KindPrintf: + pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name) return } if anyW { @@ -621,7 +635,7 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F if maxArgNum != len(call.Args) { expect := maxArgNum - firstArg numArgs := len(call.Args) - firstArg - pass.ReportRangef(call, "%s call needs %v but has %v", fn.Name(), count(expect, "arg"), count(numArgs, "arg")) + pass.ReportRangef(call, "%s call needs %v but has %v", fn.FullName(), count(expect, "arg"), count(numArgs, "arg")) } } @@ -833,8 +847,9 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o } // Could current arg implement fmt.Formatter? + // Skip check for the %w verb, which requires an error. formatter := false - if state.argNum < len(call.Args) { + if v.typ != argError && state.argNum < len(call.Args) { if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok { formatter = isFormatter(tv.Type) } @@ -870,8 +885,12 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o return } arg := call.Args[argNum] - if !matchArgType(pass, argInt, nil, arg) { - pass.ReportRangef(call, "%s format %s uses non-int %s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg)) + if reason, ok := matchArgType(pass, argInt, arg); !ok { + details := "" + if reason != "" { + details = " (" + reason + ")" + } + pass.ReportRangef(call, "%s format %s uses non-int %s%s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg), details) return false } } @@ -888,12 +907,16 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg)) return false } - if !matchArgType(pass, v.typ, nil, arg) { + if reason, ok := matchArgType(pass, v.typ, arg); !ok { typeString := "" if typ := pass.TypesInfo.Types[arg].Type; typ != nil { typeString = typ.String() } - pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString) + details := "" + if reason != "" { + details = " (" + reason + ")" + } + pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details) return false } if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) { @@ -949,7 +972,7 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) { } if id, ok := e.(*ast.Ident); ok { if pass.TypesInfo.Uses[id] == sig.Recv() { - return method.Name(), true + return method.FullName(), true } } return "", false @@ -1044,40 +1067,39 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { if x, ok := sel.X.(*ast.Ident); ok { if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { - pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.Name(), analysisutil.Format(pass.Fset, call.Args[0])) + pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.FullName(), analysisutil.Format(pass.Fset, call.Args[0])) } } } } arg := args[0] - if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { - // Ignore trailing % character in lit.Value. + if s, ok := stringConstantExpr(pass, arg); ok { + // Ignore trailing % character // The % in "abc 0.0%" couldn't be a formatting directive. - s := strings.TrimSuffix(lit.Value, `%"`) + s = strings.TrimSuffix(s, "%") if strings.Contains(s, "%") { m := printFormatRE.FindStringSubmatch(s) if m != nil { - pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.Name(), m[0]) + pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.FullName(), m[0]) } } } if strings.HasSuffix(fn.Name(), "ln") { // The last item, if a string, should not have a newline. arg = args[len(args)-1] - if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { - str, _ := strconv.Unquote(lit.Value) - if strings.HasSuffix(str, "\n") { - pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.Name()) + if s, ok := stringConstantExpr(pass, arg); ok { + if strings.HasSuffix(s, "\n") { + pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName()) } } } for _, arg := range args { if isFunctionValue(pass, arg) { - pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.Name(), analysisutil.Format(pass.Fset, arg)) + pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg)) } if methodName, ok := recursiveStringer(pass, arg); ok { - pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.Name(), analysisutil.Format(pass.Fset, arg), methodName) + pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName) } } } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go index 6a5fae44f46..270e917c809 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go @@ -5,45 +5,60 @@ package printf import ( + "fmt" "go/ast" "go/types" "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/internal/typeparams" ) var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) -// matchArgType reports an error if printf verb t is not appropriate -// for operand arg. +// matchArgType reports an error if printf verb t is not appropriate for +// operand arg. // -// typ is used only for recursive calls; external callers must supply nil. -// -// (Recursion arises from the compound types {map,chan,slice} which -// may be printed with %d etc. if that is appropriate for their element -// types.) -func matchArgType(pass *analysis.Pass, t printfArgType, typ types.Type, arg ast.Expr) bool { - return matchArgTypeInternal(pass, t, typ, arg, make(map[types.Type]bool)) -} - -// matchArgTypeInternal is the internal version of matchArgType. It carries a map -// remembering what types are in progress so we don't recur when faced with recursive -// types or mutually recursive types. -func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool { +// If arg is a type parameter, the verb t must be appropriate for every type in +// the type parameter type set. +func matchArgType(pass *analysis.Pass, t printfArgType, arg ast.Expr) (reason string, ok bool) { // %v, %T accept any argument type. if t == anyType { - return true + return "", true } + + typ := pass.TypesInfo.Types[arg].Type if typ == nil { - // external call - typ = pass.TypesInfo.Types[arg].Type - if typ == nil { - return true // probably a type check problem - } + return "", true // probably a type check problem } + m := &argMatcher{t: t, seen: make(map[types.Type]bool)} + ok = m.match(typ, true) + return m.reason, ok +} + +// argMatcher recursively matches types against the printfArgType t. +// +// To short-circuit recursion, it keeps track of types that have already been +// matched (or are in the process of being matched) via the seen map. Recursion +// arises from the compound types {map,chan,slice} which may be printed with %d +// etc. if that is appropriate for their element types, as well as from type +// parameters, which are expanded to the constituents of their type set. +// +// The reason field may be set to report the cause of the mismatch. +type argMatcher struct { + t printfArgType + seen map[types.Type]bool + reason string +} + +// match checks if typ matches m's printf arg type. If topLevel is true, typ is +// the actual type of the printf arg, for which special rules apply. As a +// special case, top level type parameters pass topLevel=true when checking for +// matches among the constituents of their type set, as type arguments will +// replace the type parameter at compile time. +func (m *argMatcher) match(typ types.Type, topLevel bool) bool { // %w accepts only errors. - if t == argError { + if m.t == argError { return types.ConvertibleTo(typ, errorType) } @@ -51,65 +66,122 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, if isFormatter(typ) { return true } + // If we can use a string, might arg (dynamically) implement the Stringer or Error interface? - if t&argString != 0 && isConvertibleToString(pass, typ) { + if m.t&argString != 0 && isConvertibleToString(typ) { + return true + } + + if typ, _ := typ.(*typeparams.TypeParam); typ != nil { + // Avoid infinite recursion through type parameters. + if m.seen[typ] { + return true + } + m.seen[typ] = true + terms, err := typeparams.StructuralTerms(typ) + if err != nil { + return true // invalid type (possibly an empty type set) + } + + if len(terms) == 0 { + // No restrictions on the underlying of typ. Type parameters implementing + // error, fmt.Formatter, or fmt.Stringer were handled above, and %v and + // %T was handled in matchType. We're about to check restrictions the + // underlying; if the underlying type is unrestricted there must be an + // element of the type set that violates one of the arg type checks + // below, so we can safely return false here. + + if m.t == anyType { // anyType must have already been handled. + panic("unexpected printfArgType") + } + return false + } + + // Only report a reason if typ is the argument type, otherwise it won't + // make sense. Note that it is not sufficient to check if topLevel == here, + // as type parameters can have a type set consisting of other type + // parameters. + reportReason := len(m.seen) == 1 + + for _, term := range terms { + if !m.match(term.Type(), topLevel) { + if reportReason { + if term.Tilde() { + m.reason = fmt.Sprintf("contains ~%s", term.Type()) + } else { + m.reason = fmt.Sprintf("contains %s", term.Type()) + } + } + return false + } + } return true } typ = typ.Underlying() - if inProgress[typ] { - // We're already looking at this type. The call that started it will take care of it. + if m.seen[typ] { + // We've already considered typ, or are in the process of considering it. + // In case we've already considered typ, it must have been valid (else we + // would have stopped matching). In case we're in the process of + // considering it, we must avoid infinite recursion. + // + // There are some pathological cases where returning true here is + // incorrect, for example `type R struct { F []R }`, but these are + // acceptable false negatives. return true } - inProgress[typ] = true + m.seen[typ] = true switch typ := typ.(type) { case *types.Signature: - return t == argPointer + return m.t == argPointer case *types.Map: - return t == argPointer || - // Recur: map[int]int matches %d. - (matchArgTypeInternal(pass, t, typ.Key(), arg, inProgress) && matchArgTypeInternal(pass, t, typ.Elem(), arg, inProgress)) + if m.t == argPointer { + return true + } + // Recur: map[int]int matches %d. + return m.match(typ.Key(), false) && m.match(typ.Elem(), false) case *types.Chan: - return t&argPointer != 0 + return m.t&argPointer != 0 case *types.Array: // Same as slice. - if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { + if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && m.t&argString != 0 { return true // %s matches []byte } // Recur: []int matches %d. - return matchArgTypeInternal(pass, t, typ.Elem(), arg, inProgress) + return m.match(typ.Elem(), false) case *types.Slice: // Same as array. - if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { + if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && m.t&argString != 0 { return true // %s matches []byte } - if t == argPointer { + if m.t == argPointer { return true // %p prints a slice's 0th element } // Recur: []int matches %d. But watch out for // type T []T // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below. - return matchArgTypeInternal(pass, t, typ.Elem(), arg, inProgress) + return m.match(typ.Elem(), false) case *types.Pointer: // Ugly, but dealing with an edge case: a known pointer to an invalid type, // probably something from a failed import. - if typ.Elem().String() == "invalid type" { - if false { - pass.Reportf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", analysisutil.Format(pass.Fset, arg)) - } + if typ.Elem() == types.Typ[types.Invalid] { return true // special case } // If it's actually a pointer with %p, it prints as one. - if t == argPointer { + if m.t == argPointer { return true } + if typeparams.IsTypeParam(typ.Elem()) { + return true // We don't know whether the logic below applies. Give up. + } + under := typ.Elem().Underlying() switch under.(type) { case *types.Struct: // see below @@ -118,19 +190,31 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, case *types.Map: // see below default: // Check whether the rest can print pointers. - return t&argPointer != 0 + return m.t&argPointer != 0 } - // If it's a top-level pointer to a struct, array, slice, or + // If it's a top-level pointer to a struct, array, slice, type param, or // map, that's equivalent in our analysis to whether we can // print the type being pointed to. Pointers in nested levels // are not supported to minimize fmt running into loops. - if len(inProgress) > 1 { + if !topLevel { return false } - return matchArgTypeInternal(pass, t, under, arg, inProgress) + return m.match(under, false) case *types.Struct: - return matchStructArgType(pass, t, typ, arg, inProgress) + // report whether all the elements of the struct match the expected type. For + // instance, with "%d" all the elements must be printable with the "%d" format. + for i := 0; i < typ.NumFields(); i++ { + typf := typ.Field(i) + if !m.match(typf.Type(), false) { + return false + } + if m.t&argString != 0 && !typf.Exported() && isConvertibleToString(typf.Type()) { + // Issue #17798: unexported Stringer or error cannot be properly formatted. + return false + } + } + return true case *types.Interface: // There's little we can do. @@ -142,7 +226,7 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, switch typ.Kind() { case types.UntypedBool, types.Bool: - return t&argBool != 0 + return m.t&argBool != 0 case types.UntypedInt, types.Int, @@ -156,35 +240,32 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, types.Uint32, types.Uint64, types.Uintptr: - return t&argInt != 0 + return m.t&argInt != 0 case types.UntypedFloat, types.Float32, types.Float64: - return t&argFloat != 0 + return m.t&argFloat != 0 case types.UntypedComplex, types.Complex64, types.Complex128: - return t&argComplex != 0 + return m.t&argComplex != 0 case types.UntypedString, types.String: - return t&argString != 0 + return m.t&argString != 0 case types.UnsafePointer: - return t&(argPointer|argInt) != 0 + return m.t&(argPointer|argInt) != 0 case types.UntypedRune: - return t&(argInt|argRune) != 0 + return m.t&(argInt|argRune) != 0 case types.UntypedNil: return false case types.Invalid: - if false { - pass.Reportf(arg.Pos(), "printf argument %v has invalid or unknown type", analysisutil.Format(pass.Fset, arg)) - } return true // Probably a type check problem. } panic("unreachable") @@ -193,7 +274,7 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, return false } -func isConvertibleToString(pass *analysis.Pass, typ types.Type) bool { +func isConvertibleToString(typ types.Type) bool { if bt, ok := typ.(*types.Basic); ok && bt.Kind() == types.UntypedNil { // We explicitly don't want untyped nil, which is // convertible to both of the interfaces below, as it @@ -228,19 +309,3 @@ func hasBasicType(pass *analysis.Pass, x ast.Expr, kind types.BasicKind) bool { b, ok := t.(*types.Basic) return ok && b.Kind() == kind } - -// matchStructArgType reports whether all the elements of the struct match the expected -// type. For instance, with "%d" all the elements must be printable with the "%d" format. -func matchStructArgType(pass *analysis.Pass, t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool { - for i := 0; i < typ.NumFields(); i++ { - typf := typ.Field(i) - if !matchArgTypeInternal(pass, t, typf.Type(), arg, inProgress) { - return false - } - if t&argString != 0 && !typf.Exported() && isConvertibleToString(pass, typf.Type()) { - // Issue #17798: unexported Stringer or error cannot be properly formatted. - return false - } - } - return true -} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go b/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go index 1f3df07ccd1..e968f27b403 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go @@ -14,11 +14,14 @@ import ( "go/ast" "go/constant" "go/token" + "go/types" + "math" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/typeparams" ) const Doc = "check for shifts that equal or exceed the width of the integer" @@ -93,9 +96,36 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) { if t == nil { return } - size := 8 * pass.TypesSizes.Sizeof(t) - if amt >= size { + var structuralTypes []types.Type + switch t := t.(type) { + case *typeparams.TypeParam: + terms, err := typeparams.StructuralTerms(t) + if err != nil { + return // invalid type + } + for _, term := range terms { + structuralTypes = append(structuralTypes, term.Type()) + } + default: + structuralTypes = append(structuralTypes, t) + } + sizes := make(map[int64]struct{}) + for _, t := range structuralTypes { + size := 8 * pass.TypesSizes.Sizeof(t) + sizes[size] = struct{}{} + } + minSize := int64(math.MaxInt64) + for size := range sizes { + if size < minSize { + minSize = size + } + } + if amt >= minSize { ident := analysisutil.Format(pass.Fset, x) - pass.ReportRangef(node, "%s (%d bits) too small for shift of %d", ident, size, amt) + qualifier := "" + if len(sizes) > 1 { + qualifier = "may be " + } + pass.ReportRangef(node, "%s (%s%d bits) too small for shift of %d", ident, qualifier, minSize, amt) } } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go b/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go index 64a28ac0b97..cc9497179da 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go @@ -61,7 +61,7 @@ var Analyzer = &analysis.Analyzer{ // we let it go. But if it does have a fmt.ScanState, then the // rest has to match. var canonicalMethods = map[string]struct{ args, results []string }{ - "As": {[]string{"interface{}"}, []string{"bool"}}, // errors.As + "As": {[]string{"any"}, []string{"bool"}}, // errors.As // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder @@ -194,7 +194,9 @@ func matchParams(pass *analysis.Pass, expect []string, actual *types.Tuple, pref func matchParamType(expect string, actual types.Type) bool { expect = strings.TrimPrefix(expect, "=") // Overkill but easy. - return typeString(actual) == expect + t := typeString(actual) + return t == expect || + (t == "any" || t == "interface{}") && (expect == "any" || expect == "interface{}") } var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/stringintconv/string.go b/libgo/go/golang.org/x/tools/go/analysis/passes/stringintconv/string.go index 7a005901e84..e41de809de1 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/stringintconv/string.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/stringintconv/string.go @@ -10,10 +10,12 @@ import ( "fmt" "go/ast" "go/types" + "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/typeparams" ) const Doc = `check for string(int) conversions @@ -36,6 +38,35 @@ var Analyzer = &analysis.Analyzer{ Run: run, } +// describe returns a string describing the type typ contained within the type +// set of inType. If non-empty, inName is used as the name of inType (this is +// necessary so that we can use alias type names that may not be reachable from +// inType itself). +func describe(typ, inType types.Type, inName string) string { + name := inName + if typ != inType { + name = typeName(typ) + } + if name == "" { + return "" + } + + var parentheticals []string + if underName := typeName(typ.Underlying()); underName != "" && underName != name { + parentheticals = append(parentheticals, underName) + } + + if typ != inType && inName != "" && inName != name { + parentheticals = append(parentheticals, "in "+inName) + } + + if len(parentheticals) > 0 { + name += " (" + strings.Join(parentheticals, ", ") + ")" + } + + return name +} + func typeName(typ types.Type) string { if v, _ := typ.(interface{ Name() string }); v != nil { return v.Name() @@ -54,6 +85,11 @@ func run(pass *analysis.Pass) (interface{}, error) { inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) + if len(call.Args) != 1 { + return + } + arg := call.Args[0] + // Retrieve target type name. var tname *types.TypeName switch fun := call.Fun.(type) { @@ -65,62 +101,119 @@ func run(pass *analysis.Pass) (interface{}, error) { if tname == nil { return } - target := tname.Name() - // Check that target type T in T(v) has an underlying type of string. - T, _ := tname.Type().Underlying().(*types.Basic) - if T == nil || T.Kind() != types.String { - return + // In the conversion T(v) of a value v of type V to a target type T, we + // look for types T0 in the type set of T and V0 in the type set of V, such + // that V0->T0 is a problematic conversion. If T and V are not type + // parameters, this amounts to just checking if V->T is a problematic + // conversion. + + // First, find a type T0 in T that has an underlying type of string. + T := tname.Type() + ttypes, err := structuralTypes(T) + if err != nil { + return // invalid type } - if s := T.Name(); target != s { - target += " (" + s + ")" + + var T0 types.Type // string type in the type set of T + + for _, tt := range ttypes { + u, _ := tt.Underlying().(*types.Basic) + if u != nil && u.Kind() == types.String { + T0 = tt + break + } } - // Check that type V of v has an underlying integral type that is not byte or rune. - if len(call.Args) != 1 { + if T0 == nil { + // No target types have an underlying type of string. return } - v := call.Args[0] - vtyp := pass.TypesInfo.TypeOf(v) - V, _ := vtyp.Underlying().(*types.Basic) - if V == nil || V.Info()&types.IsInteger == 0 { - return + + // Next, find a type V0 in V that has an underlying integral type that is + // not byte or rune. + V := pass.TypesInfo.TypeOf(arg) + vtypes, err := structuralTypes(V) + if err != nil { + return // invalid type } - switch V.Kind() { - case types.Byte, types.Rune, types.UntypedRune: - return + + var V0 types.Type // integral type in the type set of V + + for _, vt := range vtypes { + u, _ := vt.Underlying().(*types.Basic) + if u != nil && u.Info()&types.IsInteger != 0 { + switch u.Kind() { + case types.Byte, types.Rune, types.UntypedRune: + continue + } + V0 = vt + break + } } - // Retrieve source type name. - source := typeName(vtyp) - if source == "" { + if V0 == nil { + // No source types are non-byte or rune integer types. return } - if s := V.Name(); source != s { - source += " (" + s + ")" + + convertibleToRune := true // if true, we can suggest a fix + for _, t := range vtypes { + if !types.ConvertibleTo(t, types.Typ[types.Rune]) { + convertibleToRune = false + break + } + } + + target := describe(T0, T, tname.Name()) + source := describe(V0, V, typeName(V)) + + if target == "" || source == "" { + return // something went wrong } + diag := analysis.Diagnostic{ Pos: n.Pos(), Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)", source, target), - SuggestedFixes: []analysis.SuggestedFix{ + } + + if convertibleToRune { + diag.SuggestedFixes = []analysis.SuggestedFix{ { Message: "Did you mean to convert a rune to a string?", TextEdits: []analysis.TextEdit{ { - Pos: v.Pos(), - End: v.Pos(), + Pos: arg.Pos(), + End: arg.Pos(), NewText: []byte("rune("), }, { - Pos: v.End(), - End: v.End(), + Pos: arg.End(), + End: arg.End(), NewText: []byte(")"), }, }, }, - }, + } } pass.Report(diag) }) return nil, nil } + +func structuralTypes(t types.Type) ([]types.Type, error) { + var structuralTypes []types.Type + switch t := t.(type) { + case *typeparams.TypeParam: + terms, err := typeparams.StructuralTerms(t) + if err != nil { + return nil, err + } + for _, term := range terms { + structuralTypes = append(structuralTypes, term.Type()) + } + default: + structuralTypes = append(structuralTypes, t) + } + return structuralTypes, nil +} diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go b/libgo/go/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go index d2b9a5640d9..7ea8f77e335 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go @@ -11,6 +11,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/typeparams" ) const Doc = `report calls to (*testing.T).Fatal from goroutines started by a test. @@ -119,11 +120,44 @@ func typeIsTestingDotTOrB(expr ast.Expr) (string, bool) { return varTypeName, ok } +// goStmtFunc returns the ast.Node of a call expression +// that was invoked as a go statement. Currently, only +// function literals declared in the same function, and +// static calls within the same package are supported. +func goStmtFun(goStmt *ast.GoStmt) ast.Node { + switch fun := goStmt.Call.Fun.(type) { + case *ast.IndexExpr, *typeparams.IndexListExpr: + x, _, _, _ := typeparams.UnpackIndexExpr(fun) + id, _ := x.(*ast.Ident) + if id == nil { + break + } + if id.Obj == nil { + break + } + if funDecl, ok := id.Obj.Decl.(ast.Node); ok { + return funDecl + } + case *ast.Ident: + // TODO(cuonglm): improve this once golang/go#48141 resolved. + if fun.Obj == nil { + break + } + if funDecl, ok := fun.Obj.Decl.(ast.Node); ok { + return funDecl + } + case *ast.FuncLit: + return goStmt.Call.Fun + } + return goStmt.Call +} + // checkGoStmt traverses the goroutine and checks for the // use of the forbidden *testing.(B, T) methods. func checkGoStmt(pass *analysis.Pass, goStmt *ast.GoStmt) { + fn := goStmtFun(goStmt) // Otherwise examine the goroutine to check for the forbidden methods. - ast.Inspect(goStmt, func(n ast.Node) bool { + ast.Inspect(fn, func(n ast.Node) bool { selExpr, ok := n.(*ast.SelectorExpr) if !ok { return true @@ -147,7 +181,11 @@ func checkGoStmt(pass *analysis.Pass, goStmt *ast.GoStmt) { return true } if typeName, ok := typeIsTestingDotTOrB(field.Type); ok { - pass.ReportRangef(selExpr, "call to (*%s).%s from a non-test goroutine", typeName, selExpr.Sel) + var fnRange analysis.Range = goStmt + if _, ok := fn.(*ast.FuncLit); ok { + fnRange = selExpr + } + pass.ReportRangef(fnRange, "call to (*%s).%s from a non-test goroutine", typeName, selExpr.Sel) } return true }) diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go b/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go index 8232276186a..2c878824966 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go @@ -8,12 +8,15 @@ package tests import ( "go/ast" + "go/token" "go/types" + "regexp" "strings" "unicode" "unicode/utf8" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/internal/typeparams" ) const Doc = `check for common mistaken usages of tests and examples @@ -42,10 +45,10 @@ func run(pass *analysis.Pass) (interface{}, error) { // Ignore non-functions or functions with receivers. continue } - switch { case strings.HasPrefix(fn.Name.Name, "Example"): - checkExample(pass, fn) + checkExampleName(pass, fn) + checkExampleOutput(pass, fn, f.Comments) case strings.HasPrefix(fn.Name.Name, "Test"): checkTest(pass, fn, "Test") case strings.HasPrefix(fn.Name.Name, "Benchmark"): @@ -108,7 +111,59 @@ func lookup(pkg *types.Package, name string) []types.Object { return ret } -func checkExample(pass *analysis.Pass, fn *ast.FuncDecl) { +// This pattern is taken from /go/src/go/doc/example.go +var outputRe = regexp.MustCompile(`(?i)^[[:space:]]*(unordered )?output:`) + +type commentMetadata struct { + isOutput bool + pos token.Pos +} + +func checkExampleOutput(pass *analysis.Pass, fn *ast.FuncDecl, fileComments []*ast.CommentGroup) { + commentsInExample := []commentMetadata{} + numOutputs := 0 + + // Find the comment blocks that are in the example. These comments are + // guaranteed to be in order of appearance. + for _, cg := range fileComments { + if cg.Pos() < fn.Pos() { + continue + } else if cg.End() > fn.End() { + break + } + + isOutput := outputRe.MatchString(cg.Text()) + if isOutput { + numOutputs++ + } + + commentsInExample = append(commentsInExample, commentMetadata{ + isOutput: isOutput, + pos: cg.Pos(), + }) + } + + // Change message based on whether there are multiple output comment blocks. + msg := "output comment block must be the last comment block" + if numOutputs > 1 { + msg = "there can only be one output comment block per example" + } + + for i, cg := range commentsInExample { + // Check for output comments that are not the last comment in the example. + isLast := (i == len(commentsInExample)-1) + if cg.isOutput && !isLast { + pass.Report( + analysis.Diagnostic{ + Pos: cg.pos, + Message: msg, + }, + ) + } + } +} + +func checkExampleName(pass *analysis.Pass, fn *ast.FuncDecl) { fnName := fn.Name.Name if params := fn.Type.Params; len(params.List) != 0 { pass.Reportf(fn.Pos(), "%s should be niladic", fnName) @@ -116,6 +171,9 @@ func checkExample(pass *analysis.Pass, fn *ast.FuncDecl) { if results := fn.Type.Results; results != nil && len(results.List) != 0 { pass.Reportf(fn.Pos(), "%s should return nothing", fnName) } + if tparams := typeparams.ForFuncType(fn.Type); tparams != nil && len(tparams.List) > 0 { + pass.Reportf(fn.Pos(), "%s should not have type params", fnName) + } if fnName == "Example" { // Nothing more to do. @@ -182,6 +240,12 @@ func checkTest(pass *analysis.Pass, fn *ast.FuncDecl, prefix string) { return } + if tparams := typeparams.ForFuncType(fn.Type); tparams != nil && len(tparams.List) > 0 { + // Note: cmd/go/internal/load also errors about TestXXX and BenchmarkXXX functions with type parameters. + // We have currently decided to also warn before compilation/package loading. This can help users in IDEs. + pass.Reportf(fn.Pos(), "%s has type parameters: it will not be run by go test as a %sXXX function", fn.Name.Name, prefix) + } + if !isTestSuffix(fn.Name.Name[len(prefix):]) { pass.Reportf(fn.Pos(), "%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix) } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go index 92b37caff9f..5129048a076 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/typeparams" ) const Doc = `report passing non-pointer or non-interface values to unmarshal @@ -85,7 +86,7 @@ func run(pass *analysis.Pass) (interface{}, error) { t := pass.TypesInfo.Types[call.Args[argidx]].Type switch t.Underlying().(type) { - case *types.Pointer, *types.Interface: + case *types.Pointer, *types.Interface, *typeparams.TypeParam: return } diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go b/libgo/go/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go index bececee7e93..06747ba72b9 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go @@ -17,6 +17,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/typeparams" ) // TODO(adonovan): make this analysis modular: export a mustUseResult @@ -70,6 +71,11 @@ func run(pass *analysis.Pass) (interface{}, error) { return // a conversion, not a call } + x, _, _, _ := typeparams.UnpackIndexExpr(fun) + if x != nil { + fun = x // If this is generic function or method call, skip the instantiation arguments + } + selector, ok := fun.(*ast.SelectorExpr) if !ok { return // neither a method call nor a qualified ident diff --git a/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go index 323282136fb..393954a238b 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go +++ b/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go @@ -51,6 +51,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/internal/analysisflags" "golang.org/x/tools/go/analysis/internal/facts" + "golang.org/x/tools/internal/typeparams" ) // A Config describes a compilation unit to be analyzed. @@ -233,6 +234,8 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), } + typeparams.InitInstanceInfo(info) + pkg, err := tc.Check(cfg.ImportPath, fset, files, info) if err != nil { if cfg.SucceedOnTypecheckFailure { diff --git a/libgo/go/golang.org/x/tools/go/ast/astutil/enclosing.go b/libgo/go/golang.org/x/tools/go/ast/astutil/enclosing.go index 6b7052b892c..a5c6d6d4fa0 100644 --- a/libgo/go/golang.org/x/tools/go/ast/astutil/enclosing.go +++ b/libgo/go/golang.org/x/tools/go/ast/astutil/enclosing.go @@ -11,6 +11,8 @@ import ( "go/ast" "go/token" "sort" + + "golang.org/x/tools/internal/typeparams" ) // PathEnclosingInterval returns the node that encloses the source @@ -294,8 +296,8 @@ func childrenOf(n ast.Node) []ast.Node { case *ast.FieldList: children = append(children, - tok(n.Opening, len("(")), - tok(n.Closing, len(")"))) + tok(n.Opening, len("(")), // or len("[") + tok(n.Closing, len(")"))) // or len("]") case *ast.File: // TODO test: Doc @@ -322,6 +324,9 @@ func childrenOf(n ast.Node) []ast.Node { children = append(children, n.Recv) } children = append(children, n.Name) + if tparams := typeparams.ForFuncType(n.Type); tparams != nil { + children = append(children, tparams) + } if n.Type.Params != nil { children = append(children, n.Type.Params) } @@ -371,8 +376,13 @@ func childrenOf(n ast.Node) []ast.Node { case *ast.IndexExpr: children = append(children, - tok(n.Lbrack, len("{")), - tok(n.Rbrack, len("}"))) + tok(n.Lbrack, len("[")), + tok(n.Rbrack, len("]"))) + + case *typeparams.IndexListExpr: + children = append(children, + tok(n.Lbrack, len("[")), + tok(n.Rbrack, len("]"))) case *ast.InterfaceType: children = append(children, @@ -581,6 +591,8 @@ func NodeDescription(n ast.Node) string { return "decrement statement" case *ast.IndexExpr: return "index expression" + case *typeparams.IndexListExpr: + return "index list expression" case *ast.InterfaceType: return "interface type" case *ast.KeyValueExpr: diff --git a/libgo/go/golang.org/x/tools/go/ast/astutil/rewrite.go b/libgo/go/golang.org/x/tools/go/ast/astutil/rewrite.go index cf72ea990bd..6d9ca23e2b0 100644 --- a/libgo/go/golang.org/x/tools/go/ast/astutil/rewrite.go +++ b/libgo/go/golang.org/x/tools/go/ast/astutil/rewrite.go @@ -9,6 +9,8 @@ import ( "go/ast" "reflect" "sort" + + "golang.org/x/tools/internal/typeparams" ) // An ApplyFunc is invoked by Apply for each node n, even if n is nil, @@ -251,6 +253,10 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. a.apply(n, "X", nil, n.X) a.apply(n, "Index", nil, n.Index) + case *typeparams.IndexListExpr: + a.apply(n, "X", nil, n.X) + a.applyList(n, "Indices") + case *ast.SliceExpr: a.apply(n, "X", nil, n.X) a.apply(n, "Low", nil, n.Low) diff --git a/libgo/go/golang.org/x/tools/go/ast/inspector/typeof.go b/libgo/go/golang.org/x/tools/go/ast/inspector/typeof.go index b6b00cf2e1e..11f4fc369a0 100644 --- a/libgo/go/golang.org/x/tools/go/ast/inspector/typeof.go +++ b/libgo/go/golang.org/x/tools/go/ast/inspector/typeof.go @@ -9,7 +9,11 @@ package inspector // The initial map-based implementation was too slow; // see https://go-review.googlesource.com/c/tools/+/135655/1/go/ast/inspector/inspector.go#196 -import "go/ast" +import ( + "go/ast" + + "golang.org/x/tools/internal/typeparams" +) const ( nArrayType = iota @@ -47,6 +51,7 @@ const ( nImportSpec nIncDecStmt nIndexExpr + nIndexListExpr nInterfaceType nKeyValueExpr nLabeledStmt @@ -164,6 +169,8 @@ func typeOf(n ast.Node) uint64 { return 1 << nIncDecStmt case *ast.IndexExpr: return 1 << nIndexExpr + case *typeparams.IndexListExpr: + return 1 << nIndexListExpr case *ast.InterfaceType: return 1 << nInterfaceType case *ast.KeyValueExpr: diff --git a/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go b/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go index cffd7acbee7..7e96fc234e5 100644 --- a/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/libgo/go/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -23,10 +23,12 @@ package objectpath import ( "fmt" + "go/types" + "sort" "strconv" "strings" - "go/types" + "golang.org/x/tools/internal/typeparams" ) // A Path is an opaque name that identifies a types.Object @@ -57,12 +59,16 @@ type Path string // - The only PO operator is Package.Scope.Lookup, which requires an identifier. // - The only OT operator is Object.Type, // which we encode as '.' because dot cannot appear in an identifier. -// - The TT operators are encoded as [EKPRU]. -// - The OT operators are encoded as [AFMO]; +// - The TT operators are encoded as [EKPRUTC]; +// one of these (TypeParam) requires an integer operand, +// which is encoded as a string of decimal digits. +// - The TO operators are encoded as [AFMO]; // three of these (At,Field,Method) require an integer operand, // which is encoded as a string of decimal digits. // These indices are stable across different representations // of the same package, even source and export data. +// The indices used are implementation specific and may not correspond to +// the argument to the go/types function. // // In the example below, // @@ -89,17 +95,19 @@ const ( opType = '.' // .Type() (Object) // type->type operators - opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map) - opKey = 'K' // .Key() (Map) - opParams = 'P' // .Params() (Signature) - opResults = 'R' // .Results() (Signature) - opUnderlying = 'U' // .Underlying() (Named) + opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map) + opKey = 'K' // .Key() (Map) + opParams = 'P' // .Params() (Signature) + opResults = 'R' // .Results() (Signature) + opUnderlying = 'U' // .Underlying() (Named) + opTypeParam = 'T' // .TypeParams.At(i) (Named, Signature) + opConstraint = 'C' // .Constraint() (TypeParam) // type->object operators - opAt = 'A' // .At(i) (Tuple) - opField = 'F' // .Field(i) (Struct) - opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored) - opObj = 'O' // .Obj() (Named) + opAt = 'A' // .At(i) (Tuple) + opField = 'F' // .Field(i) (Struct) + opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored) + opObj = 'O' // .Obj() (Named, TypeParam) ) // The For function returns the path to an object relative to its package, @@ -190,10 +198,15 @@ func For(obj types.Object) (Path, error) { // 3. Not a package-level object. // Reject obviously non-viable cases. switch obj := obj.(type) { + case *types.TypeName: + if _, ok := obj.Type().(*typeparams.TypeParam); !ok { + // With the exception of type parameters, only package-level type names + // have a path. + return "", fmt.Errorf("no path for %v", obj) + } case *types.Const, // Only package-level constants have a path. - *types.TypeName, // Only package-level types have a path. - *types.Label, // Labels are function-local. - *types.PkgName: // PkgNames are file-local. + *types.Label, // Labels are function-local. + *types.PkgName: // PkgNames are file-local. return "", fmt.Errorf("no path for %v", obj) case *types.Var: @@ -245,6 +258,12 @@ func For(obj types.Object) (Path, error) { return Path(r), nil } } else { + if named, _ := T.(*types.Named); named != nil { + if r := findTypeParam(obj, typeparams.ForNamed(named), path); r != nil { + // generic named type + return Path(r), nil + } + } // defined (named) type if r := find(obj, T.Underlying(), append(path, opUnderlying)); r != nil { return Path(r), nil @@ -270,8 +289,12 @@ func For(obj types.Object) (Path, error) { // Inspect declared methods of defined types. if T, ok := o.Type().(*types.Named); ok { path = append(path, opType) - for i := 0; i < T.NumMethods(); i++ { - m := T.Method(i) + // Note that method index here is always with respect + // to canonical ordering of methods, regardless of how + // they appear in the underlying type. + canonical := canonicalize(T) + for i := 0; i < len(canonical); i++ { + m := canonical[i] path2 := appendOpArg(path, opMethod, i) if m == obj { return Path(path2), nil // found declared method @@ -313,6 +336,9 @@ func find(obj types.Object, T types.Type, path []byte) []byte { } return find(obj, T.Elem(), append(path, opElem)) case *types.Signature: + if r := findTypeParam(obj, typeparams.ForSignature(T), path); r != nil { + return r + } if r := find(obj, T.Params(), append(path, opParams)); r != nil { return r } @@ -353,10 +379,30 @@ func find(obj types.Object, T types.Type, path []byte) []byte { } } return nil + case *typeparams.TypeParam: + name := T.Obj() + if name == obj { + return append(path, opObj) + } + if r := find(obj, T.Constraint(), append(path, opConstraint)); r != nil { + return r + } + return nil } panic(T) } +func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte) []byte { + for i := 0; i < list.Len(); i++ { + tparam := list.At(i) + path2 := appendOpArg(path, opTypeParam, i) + if r := find(obj, tparam, path2); r != nil { + return r + } + } + return nil +} + // Object returns the object denoted by path p within the package pkg. func Object(pkg *types.Package, p Path) (types.Object, error) { if p == "" { @@ -381,10 +427,13 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { type hasElem interface { Elem() types.Type } - // abstraction of *types.{Interface,Named} - type hasMethods interface { - Method(int) *types.Func - NumMethods() int + // abstraction of *types.{Named,Signature} + type hasTypeParams interface { + TypeParams() *typeparams.TypeParamList + } + // abstraction of *types.{Named,TypeParam} + type hasObj interface { + Obj() *types.TypeName } // The loop state is the pair (t, obj), @@ -401,7 +450,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { // Codes [AFM] have an integer operand. var index int switch code { - case opAt, opField, opMethod: + case opAt, opField, opMethod, opTypeParam: rest := strings.TrimLeft(suffix, "0123456789") numerals := suffix[:len(suffix)-len(rest)] suffix = rest @@ -466,14 +515,32 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { case opUnderlying: named, ok := t.(*types.Named) if !ok { - return nil, fmt.Errorf("cannot apply %q to %s (got %s, want named)", code, t, t) + return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named)", code, t, t) } t = named.Underlying() + case opTypeParam: + hasTypeParams, ok := t.(hasTypeParams) // Named, Signature + if !ok { + return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or signature)", code, t, t) + } + tparams := hasTypeParams.TypeParams() + if n := tparams.Len(); index >= n { + return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n) + } + t = tparams.At(index) + + case opConstraint: + tparam, ok := t.(*typeparams.TypeParam) + if !ok { + return nil, fmt.Errorf("cannot apply %q to %s (got %T, want type parameter)", code, t, t) + } + t = tparam.Constraint() + case opAt: tuple, ok := t.(*types.Tuple) if !ok { - return nil, fmt.Errorf("cannot apply %q to %s (got %s, want tuple)", code, t, t) + return nil, fmt.Errorf("cannot apply %q to %s (got %T, want tuple)", code, t, t) } if n := tuple.Len(); index >= n { return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n) @@ -495,20 +562,21 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { case opMethod: hasMethods, ok := t.(hasMethods) // Interface or Named if !ok { - return nil, fmt.Errorf("cannot apply %q to %s (got %s, want interface or named)", code, t, t) + return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t) } - if n := hasMethods.NumMethods(); index >= n { + canonical := canonicalize(hasMethods) + if n := len(canonical); index >= n { return nil, fmt.Errorf("method index %d out of range [0-%d)", index, n) } - obj = hasMethods.Method(index) + obj = canonical[index] t = nil case opObj: - named, ok := t.(*types.Named) + hasObj, ok := t.(hasObj) if !ok { - return nil, fmt.Errorf("cannot apply %q to %s (got %s, want named)", code, t, t) + return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or type param)", code, t, t) } - obj = named.Obj() + obj = hasObj.Obj() t = nil default: @@ -522,3 +590,28 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { return obj, nil // success } + +// hasMethods is an abstraction of *types.{Interface,Named}. This is pulled up +// because it is used by methodOrdering, which is in turn used by both encoding +// and decoding. +type hasMethods interface { + Method(int) *types.Func + NumMethods() int +} + +// canonicalize returns a canonical order for the methods in a hasMethod. +func canonicalize(hm hasMethods) []*types.Func { + count := hm.NumMethods() + if count <= 0 { + return nil + } + canon := make([]*types.Func, count) + for i := 0; i < count; i++ { + canon[i] = hm.Method(i) + } + less := func(i, j int) bool { + return canon[i].Id() < canon[j].Id() + } + sort.Slice(canon, less) + return canon +} diff --git a/libgo/go/golang.org/x/tools/go/types/typeutil/callee.go b/libgo/go/golang.org/x/tools/go/types/typeutil/callee.go index 38f596daf9e..90b3ab0e21c 100644 --- a/libgo/go/golang.org/x/tools/go/types/typeutil/callee.go +++ b/libgo/go/golang.org/x/tools/go/types/typeutil/callee.go @@ -9,13 +9,29 @@ import ( "go/types" "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/internal/typeparams" ) // Callee returns the named target of a function call, if any: // a function, method, builtin, or variable. +// +// Functions and methods may potentially have type parameters. func Callee(info *types.Info, call *ast.CallExpr) types.Object { + fun := astutil.Unparen(call.Fun) + + // Look through type instantiation if necessary. + isInstance := false + switch fun.(type) { + case *ast.IndexExpr, *typeparams.IndexListExpr: + // When extracting the callee from an *IndexExpr, we need to check that + // it is a *types.Func and not a *types.Var. + // Example: Don't match a slice m within the expression `m[0]()`. + isInstance = true + fun, _, _, _ = typeparams.UnpackIndexExpr(fun) + } + var obj types.Object - switch fun := astutil.Unparen(call.Fun).(type) { + switch fun := fun.(type) { case *ast.Ident: obj = info.Uses[fun] // type, var, builtin, or declared func case *ast.SelectorExpr: @@ -28,11 +44,18 @@ func Callee(info *types.Info, call *ast.CallExpr) types.Object { if _, ok := obj.(*types.TypeName); ok { return nil // T(x) is a conversion, not a call } + // A Func is required to match instantiations. + if _, ok := obj.(*types.Func); isInstance && !ok { + return nil // Was not a Func. + } return obj } -// StaticCallee returns the target (function or method) of a static -// function call, if any. It returns nil for calls to builtins. +// StaticCallee returns the target (function or method) of a static function +// call, if any. It returns nil for calls to builtins. +// +// Note: for calls of instantiated functions and methods, StaticCallee returns +// the corresponding generic function or method on the generic type. func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func { if f, ok := Callee(info, call).(*types.Func); ok && !interfaceMethod(f) { return f diff --git a/libgo/go/golang.org/x/tools/go/types/typeutil/map.go b/libgo/go/golang.org/x/tools/go/types/typeutil/map.go index c7f75450064..490ee904a62 100644 --- a/libgo/go/golang.org/x/tools/go/types/typeutil/map.go +++ b/libgo/go/golang.org/x/tools/go/types/typeutil/map.go @@ -11,6 +11,8 @@ import ( "fmt" "go/types" "reflect" + + "golang.org/x/tools/internal/typeparams" ) // Map is a hash-table-based mapping from types (types.Type) to @@ -211,11 +213,29 @@ func (m *Map) KeysString() string { // Call MakeHasher to create a Hasher. type Hasher struct { memo map[types.Type]uint32 + + // ptrMap records pointer identity. + ptrMap map[interface{}]uint32 + + // sigTParams holds type parameters from the signature being hashed. + // Signatures are considered identical modulo renaming of type parameters, so + // within the scope of a signature type the identity of the signature's type + // parameters is just their index. + // + // Since the language does not currently support referring to uninstantiated + // generic types or functions, and instantiated signatures do not have type + // parameter lists, we should never encounter a second non-empty type + // parameter list when hashing a generic signature. + sigTParams *typeparams.TypeParamList } // MakeHasher returns a new Hasher instance. func MakeHasher() Hasher { - return Hasher{make(map[types.Type]uint32)} + return Hasher{ + memo: make(map[types.Type]uint32), + ptrMap: make(map[interface{}]uint32), + sigTParams: nil, + } } // Hash computes a hash value for the given type t such that @@ -273,17 +293,62 @@ func (h Hasher) hashFor(t types.Type) uint32 { if t.Variadic() { hash *= 8863 } + + // Use a separate hasher for types inside of the signature, where type + // parameter identity is modified to be (index, constraint). We must use a + // new memo for this hasher as type identity may be affected by this + // masking. For example, in func[T any](*T), the identity of *T depends on + // whether we are mapping the argument in isolation, or recursively as part + // of hashing the signature. + // + // We should never encounter a generic signature while hashing another + // generic signature, but defensively set sigTParams only if h.mask is + // unset. + tparams := typeparams.ForSignature(t) + if h.sigTParams == nil && tparams.Len() != 0 { + h = Hasher{ + // There may be something more efficient than discarding the existing + // memo, but it would require detecting whether types are 'tainted' by + // references to type parameters. + memo: make(map[types.Type]uint32), + // Re-using ptrMap ensures that pointer identity is preserved in this + // hasher. + ptrMap: h.ptrMap, + sigTParams: tparams, + } + } + + for i := 0; i < tparams.Len(); i++ { + tparam := tparams.At(i) + hash += 7 * h.Hash(tparam.Constraint()) + } + return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) + case *typeparams.Union: + return h.hashUnion(t) + case *types.Interface: + // Interfaces are identical if they have the same set of methods, with + // identical names and types, and they have the same set of type + // restrictions. See go/types.identical for more details. var hash uint32 = 9103 + + // Hash methods. for i, n := 0, t.NumMethods(); i < n; i++ { - // See go/types.identicalMethods for rationale. // Method order is not significant. // Ignore m.Pkg(). m := t.Method(i) hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type()) } + + // Hash type restrictions. + terms, err := typeparams.InterfaceTermSet(t) + // if err != nil t has invalid type restrictions. + if err == nil { + hash += h.hashTermSet(terms) + } + return hash case *types.Map: @@ -293,13 +358,22 @@ func (h Hasher) hashFor(t types.Type) uint32 { return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem()) case *types.Named: - // Not safe with a copying GC; objects may move. - return uint32(reflect.ValueOf(t.Obj()).Pointer()) + hash := h.hashPtr(t.Obj()) + targs := typeparams.NamedTypeArgs(t) + for i := 0; i < targs.Len(); i++ { + targ := targs.At(i) + hash += 2 * h.Hash(targ) + } + return hash + + case *typeparams.TypeParam: + return h.hashTypeParam(t) case *types.Tuple: return h.hashTuple(t) } - panic(t) + + panic(fmt.Sprintf("%T: %v", t, t)) } func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { @@ -311,3 +385,57 @@ func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { } return hash } + +func (h Hasher) hashUnion(t *typeparams.Union) uint32 { + // Hash type restrictions. + terms, err := typeparams.UnionTermSet(t) + // if err != nil t has invalid type restrictions. Fall back on a non-zero + // hash. + if err != nil { + return 9151 + } + return h.hashTermSet(terms) +} + +func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 { + var hash uint32 = 9157 + 2*uint32(len(terms)) + for _, term := range terms { + // term order is not significant. + termHash := h.Hash(term.Type()) + if term.Tilde() { + termHash *= 9161 + } + hash += 3 * termHash + } + return hash +} + +// hashTypeParam returns a hash of the type parameter t, with a hash value +// depending on whether t is contained in h.sigTParams. +// +// If h.sigTParams is set and contains t, then we are in the process of hashing +// a signature, and the hash value of t must depend only on t's index and +// constraint: signatures are considered identical modulo type parameter +// renaming. +// +// Otherwise the hash of t depends only on t's pointer identity. +func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 { + if h.sigTParams != nil { + i := t.Index() + if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) { + return 9173 + 2*h.Hash(t.Constraint()) + 3*uint32(i) + } + } + return h.hashPtr(t.Obj()) +} + +// hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that +// pointers values are not dependent on the GC. +func (h Hasher) hashPtr(ptr interface{}) uint32 { + if hash, ok := h.ptrMap[ptr]; ok { + return hash + } + hash := uint32(reflect.ValueOf(ptr).Pointer()) + h.ptrMap[ptr] = hash + return hash +} diff --git a/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/input.go b/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/input.go index ac377035ec6..c1038163f1a 100644 --- a/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/input.go +++ b/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/input.go @@ -27,23 +27,23 @@ const ( // RuneRoles detects the roles of each byte rune in an input string and stores it in the output // slice. The rune role depends on the input type. Stops when it parsed all the runes in the string // or when it filled the output. If output is nil, then it gets created. -func RuneRoles(str string, reuse []RuneRole) []RuneRole { +func RuneRoles(candidate []byte, reuse []RuneRole) []RuneRole { var output []RuneRole - if cap(reuse) < len(str) { - output = make([]RuneRole, 0, len(str)) + if cap(reuse) < len(candidate) { + output = make([]RuneRole, 0, len(candidate)) } else { output = reuse[:0] } prev, prev2 := rtNone, rtNone - for i := 0; i < len(str); i++ { - r := rune(str[i]) + for i := 0; i < len(candidate); i++ { + r := rune(candidate[i]) role := RNone curr := rtLower - if str[i] <= unicode.MaxASCII { - curr = runeType(rt[str[i]] - '0') + if candidate[i] <= unicode.MaxASCII { + curr = runeType(rt[candidate[i]] - '0') } if curr == rtLower { @@ -58,7 +58,7 @@ func RuneRoles(str string, reuse []RuneRole) []RuneRole { if prev == rtUpper { // This and previous characters are both upper case. - if i+1 == len(str) { + if i+1 == len(candidate) { // This is last character, previous was also uppercase -> this is UCTail // i.e., (current char is C): aBC / BC / ABC role = RUCTail @@ -118,11 +118,26 @@ func LastSegment(input string, roles []RuneRole) string { return input[start+1 : end+1] } -// ToLower transforms the input string to lower case, which is stored in the output byte slice. +// fromChunks copies string chunks into the given buffer. +func fromChunks(chunks []string, buffer []byte) []byte { + ii := 0 + for _, chunk := range chunks { + for i := 0; i < len(chunk); i++ { + if ii >= cap(buffer) { + break + } + buffer[ii] = chunk[i] + ii++ + } + } + return buffer[:ii] +} + +// toLower transforms the input string to lower case, which is stored in the output byte slice. // The lower casing considers only ASCII values - non ASCII values are left unmodified. // Stops when parsed all input or when it filled the output slice. If output is nil, then it gets // created. -func ToLower(input string, reuse []byte) []byte { +func toLower(input []byte, reuse []byte) []byte { output := reuse if cap(reuse) < len(input) { output = make([]byte, len(input)) @@ -130,7 +145,7 @@ func ToLower(input string, reuse []byte) []byte { for i := 0; i < len(input); i++ { r := rune(input[i]) - if r <= unicode.MaxASCII { + if input[i] <= unicode.MaxASCII { if 'A' <= r && r <= 'Z' { r += 'a' - 'A' } diff --git a/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/matcher.go b/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/matcher.go index 16a643097de..265cdcf1604 100644 --- a/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/matcher.go +++ b/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/matcher.go @@ -51,8 +51,12 @@ type Matcher struct { lastCandidateLen int // in bytes lastCandidateMatched bool - // Here we save the last candidate in lower-case. This is basically a byte slice we reuse for - // performance reasons, so the slice is not reallocated for every candidate. + // Reusable buffers to avoid allocating for every candidate. + // - inputBuf stores the concatenated input chunks + // - lowerBuf stores the last candidate in lower-case + // - rolesBuf stores the calculated roles for each rune in the last + // candidate. + inputBuf [MaxInputSize]byte lowerBuf [MaxInputSize]byte rolesBuf [MaxInputSize]RuneRole } @@ -72,7 +76,7 @@ func NewMatcher(pattern string) *Matcher { m := &Matcher{ pattern: pattern, - patternLower: ToLower(pattern, nil), + patternLower: toLower([]byte(pattern), nil), } for i, c := range m.patternLower { @@ -88,7 +92,7 @@ func NewMatcher(pattern string) *Matcher { m.patternShort = m.patternLower } - m.patternRoles = RuneRoles(pattern, nil) + m.patternRoles = RuneRoles([]byte(pattern), nil) if len(pattern) > 0 { maxCharScore := 4 @@ -102,10 +106,15 @@ func NewMatcher(pattern string) *Matcher { // This is not designed for parallel use. Multiple candidates must be scored sequentially. // Returns a score between 0 and 1 (0 - no match, 1 - perfect match). func (m *Matcher) Score(candidate string) float32 { + return m.ScoreChunks([]string{candidate}) +} + +func (m *Matcher) ScoreChunks(chunks []string) float32 { + candidate := fromChunks(chunks, m.inputBuf[:]) if len(candidate) > MaxInputSize { candidate = candidate[:MaxInputSize] } - lower := ToLower(candidate, m.lowerBuf[:]) + lower := toLower(candidate, m.lowerBuf[:]) m.lastCandidateLen = len(candidate) if len(m.pattern) == 0 { @@ -174,7 +183,7 @@ func (m *Matcher) MatchedRanges() []int { return ret } -func (m *Matcher) match(candidate string, candidateLower []byte) bool { +func (m *Matcher) match(candidate []byte, candidateLower []byte) bool { i, j := 0, 0 for ; i < len(candidateLower) && j < len(m.patternLower); i++ { if candidateLower[i] == m.patternLower[j] { @@ -192,7 +201,7 @@ func (m *Matcher) match(candidate string, candidateLower []byte) bool { return true } -func (m *Matcher) computeScore(candidate string, candidateLower []byte) int { +func (m *Matcher) computeScore(candidate []byte, candidateLower []byte) int { pattLen, candLen := len(m.pattern), len(candidate) for j := 0; j <= len(m.pattern); j++ { diff --git a/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/symbol.go b/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/symbol.go new file mode 100644 index 00000000000..df9fbd51410 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/lsp/fuzzy/symbol.go @@ -0,0 +1,236 @@ +// Copyright 2021 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 fuzzy + +import ( + "unicode" +) + +// SymbolMatcher implements a fuzzy matching algorithm optimized for Go symbols +// of the form: +// example.com/path/to/package.object.field +// +// Knowing that we are matching symbols like this allows us to make the +// following optimizations: +// - We can incorporate right-to-left relevance directly into the score +// calculation. +// - We can match from right to left, discarding leading bytes if the input is +// too long. +// - We just take the right-most match without losing too much precision. This +// allows us to use an O(n) algorithm. +// - We can operate directly on chunked strings; in many cases we will +// be storing the package path and/or package name separately from the +// symbol or identifiers, so doing this avoids allocating strings. +// - We can return the index of the right-most match, allowing us to trim +// irrelevant qualification. +// +// This implementation is experimental, serving as a reference fast algorithm +// to compare to the fuzzy algorithm implemented by Matcher. +type SymbolMatcher struct { + // Using buffers of length 256 is both a reasonable size for most qualified + // symbols, and makes it easy to avoid bounds checks by using uint8 indexes. + pattern [256]rune + patternLen uint8 + inputBuffer [256]rune // avoid allocating when considering chunks + roles [256]uint32 // which roles does a rune play (word start, etc.) + segments [256]uint8 // how many segments from the right is each rune +} + +const ( + segmentStart uint32 = 1 << iota + wordStart + separator +) + +// NewSymbolMatcher creates a SymbolMatcher that may be used to match the given +// search pattern. +// +// Currently this matcher only accepts case-insensitive fuzzy patterns. +// +// An empty pattern matches no input. +func NewSymbolMatcher(pattern string) *SymbolMatcher { + m := &SymbolMatcher{} + for _, p := range pattern { + m.pattern[m.patternLen] = unicode.ToLower(p) + m.patternLen++ + if m.patternLen == 255 || int(m.patternLen) == len(pattern) { + // break at 255 so that we can represent patternLen with a uint8. + break + } + } + return m +} + +// Match looks for the right-most match of the search pattern within the symbol +// represented by concatenating the given chunks, returning its offset and +// score. +// +// If a match is found, the first return value will hold the absolute byte +// offset within all chunks for the start of the symbol. In other words, the +// index of the match within strings.Join(chunks, ""). If no match is found, +// the first return value will be -1. +// +// The second return value will be the score of the match, which is always +// between 0 and 1, inclusive. A score of 0 indicates no match. +func (m *SymbolMatcher) Match(chunks []string) (int, float64) { + // Explicit behavior for an empty pattern. + // + // As a minor optimization, this also avoids nilness checks later on, since + // the compiler can prove that m != nil. + if m.patternLen == 0 { + return -1, 0 + } + + // First phase: populate the input buffer with lower-cased runes. + // + // We could also check for a forward match here, but since we'd have to write + // the entire input anyway this has negligible impact on performance. + + var ( + inputLen = uint8(0) + modifiers = wordStart | segmentStart + ) + +input: + for _, chunk := range chunks { + for _, r := range chunk { + if r == '.' || r == '/' { + modifiers |= separator + } + // optimization: avoid calls to unicode.ToLower, which can't be inlined. + l := r + if r <= unicode.MaxASCII { + if 'A' <= r && r <= 'Z' { + l = r + 'a' - 'A' + } + } else { + l = unicode.ToLower(r) + } + if l != r { + modifiers |= wordStart + } + m.inputBuffer[inputLen] = l + m.roles[inputLen] = modifiers + inputLen++ + if m.roles[inputLen-1]&separator != 0 { + modifiers = wordStart | segmentStart + } else { + modifiers = 0 + } + // TODO: we should prefer the right-most input if it overflows, rather + // than the left-most as we're doing here. + if inputLen == 255 { + break input + } + } + } + + // Second phase: find the right-most match, and count segments from the + // right. + + var ( + pi = uint8(m.patternLen - 1) // pattern index + p = m.pattern[pi] // pattern rune + start = -1 // start offset of match + rseg = uint8(0) + ) + const maxSeg = 3 // maximum number of segments from the right to count, for scoring purposes. + + for ii := inputLen - 1; ; ii-- { + r := m.inputBuffer[ii] + if rseg < maxSeg && m.roles[ii]&separator != 0 { + rseg++ + } + m.segments[ii] = rseg + if p == r { + if pi == 0 { + start = int(ii) + break + } + pi-- + p = m.pattern[pi] + } + // Don't check ii >= 0 in the loop condition: ii is a uint8. + if ii == 0 { + break + } + } + + if start < 0 { + // no match: skip scoring + return -1, 0 + } + + // Third phase: find the shortest match, and compute the score. + + // Score is the average score for each character. + // + // A character score is the multiple of: + // 1. 1.0 if the character starts a segment, .8 if the character start a + // mid-segment word, otherwise 0.6. This carries over to immediately + // following characters. + // 2. For the final character match, the multiplier from (1) is reduced to + // .8 if the next character in the input is a mid-segment word, or 0.6 if + // the next character in the input is not a word or segment start. This + // ensures that we favor whole-word or whole-segment matches over prefix + // matches. + // 3. 1.0 if the character is part of the last segment, otherwise + // 1.0-.2*<segments from the right>, with a max segment count of 3. + // + // This is a very naive algorithm, but it is fast. There's lots of prior art + // here, and we should leverage it. For example, we could explicitly consider + // character distance, and exact matches of words or segments. + // + // Also note that this might not actually find the highest scoring match, as + // doing so could require a non-linear algorithm, depending on how the score + // is calculated. + + pi = 0 + p = m.pattern[pi] + + const ( + segStreak = 1.0 + wordStreak = 0.8 + noStreak = 0.6 + perSegment = 0.2 // we count at most 3 segments above + ) + + streakBonus := noStreak + totScore := 0.0 + for ii := uint8(start); ii < inputLen; ii++ { + r := m.inputBuffer[ii] + if r == p { + pi++ + p = m.pattern[pi] + // Note: this could be optimized with some bit operations. + switch { + case m.roles[ii]&segmentStart != 0 && segStreak > streakBonus: + streakBonus = segStreak + case m.roles[ii]&wordStart != 0 && wordStreak > streakBonus: + streakBonus = wordStreak + } + finalChar := pi >= m.patternLen + // finalCost := 1.0 + if finalChar && streakBonus > noStreak { + switch { + case ii == inputLen-1 || m.roles[ii+1]&segmentStart != 0: + // Full segment: no reduction + case m.roles[ii+1]&wordStart != 0: + streakBonus = wordStreak + default: + streakBonus = noStreak + } + } + totScore += streakBonus * (1.0 - float64(m.segments[ii])*perSegment) + if finalChar { + break + } + } else { + streakBonus = noStreak + } + } + + return start, totScore / float64(m.patternLen) +} diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/common.go b/libgo/go/golang.org/x/tools/internal/typeparams/common.go new file mode 100644 index 00000000000..1222764b6a3 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/common.go @@ -0,0 +1,79 @@ +// Copyright 2021 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 typeparams contains common utilities for writing tools that interact +// with generic Go code, as introduced with Go 1.18. +// +// Many of the types and functions in this package are proxies for the new APIs +// introduced in the standard library with Go 1.18. For example, the +// typeparams.Union type is an alias for go/types.Union, and the ForTypeSpec +// function returns the value of the go/ast.TypeSpec.TypeParams field. At Go +// versions older than 1.18 these helpers are implemented as stubs, allowing +// users of this package to write code that handles generic constructs inline, +// even if the Go version being used to compile does not support generics. +// +// Additionally, this package contains common utilities for working with the +// new generic constructs, to supplement the standard library APIs. Notably, +// the StructuralTerms API computes a minimal representation of the structural +// restrictions on a type parameter. In the future, this API may be available +// from go/types. +// +// See the example/README.md for a more detailed guide on how to update tools +// to support generics. +package typeparams + +import ( + "go/ast" + "go/token" + "go/types" +) + +// UnpackIndexExpr extracts data from AST nodes that represent index +// expressions. +// +// For an ast.IndexExpr, the resulting indices slice will contain exactly one +// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable +// number of index expressions. +// +// For nodes that don't represent index expressions, the first return value of +// UnpackIndexExpr will be nil. +func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) { + switch e := n.(type) { + case *ast.IndexExpr: + return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack + case *IndexListExpr: + return e.X, e.Lbrack, e.Indices, e.Rbrack + } + return nil, token.NoPos, nil, token.NoPos +} + +// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on +// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0 +// will panic. +func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr { + switch len(indices) { + case 0: + panic("empty indices") + case 1: + return &ast.IndexExpr{ + X: x, + Lbrack: lbrack, + Index: indices[0], + Rbrack: rbrack, + } + default: + return &IndexListExpr{ + X: x, + Lbrack: lbrack, + Indices: indices, + Rbrack: rbrack, + } + } +} + +// IsTypeParam reports whether t is a type parameter. +func IsTypeParam(t types.Type) bool { + _, ok := t.(*TypeParam) + return ok +} diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/enabled_go117.go b/libgo/go/golang.org/x/tools/internal/typeparams/enabled_go117.go new file mode 100644 index 00000000000..18212390e19 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/enabled_go117.go @@ -0,0 +1,12 @@ +// Copyright 2021 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. + +//go:build !go1.18 +// +build !go1.18 + +package typeparams + +// Enabled reports whether type parameters are enabled in the current build +// environment. +const Enabled = false diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/enabled_go118.go b/libgo/go/golang.org/x/tools/internal/typeparams/enabled_go118.go new file mode 100644 index 00000000000..d67148823c4 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/enabled_go118.go @@ -0,0 +1,15 @@ +// Copyright 2021 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. + +//go:build go1.18 +// +build go1.18 + +package typeparams + +// Note: this constant is in a separate file as this is the only acceptable +// diff between the <1.18 API of this package and the 1.18 API. + +// Enabled reports whether type parameters are enabled in the current build +// environment. +const Enabled = true diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/normalize.go b/libgo/go/golang.org/x/tools/internal/typeparams/normalize.go new file mode 100644 index 00000000000..090f142a5f3 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/normalize.go @@ -0,0 +1,216 @@ +// Copyright 2021 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 typeparams + +import ( + "errors" + "fmt" + "go/types" + "os" + "strings" +) + +//go:generate go run copytermlist.go + +const debug = false + +var ErrEmptyTypeSet = errors.New("empty type set") + +// StructuralTerms returns a slice of terms representing the normalized +// structural type restrictions of a type parameter, if any. +// +// Structural type restrictions of a type parameter are created via +// non-interface types embedded in its constraint interface (directly, or via a +// chain of interface embeddings). For example, in the declaration +// type T[P interface{~int; m()}] int +// the structural restriction of the type parameter P is ~int. +// +// With interface embedding and unions, the specification of structural type +// restrictions may be arbitrarily complex. For example, consider the +// following: +// +// type A interface{ ~string|~[]byte } +// +// type B interface{ int|string } +// +// type C interface { ~string|~int } +// +// type T[P interface{ A|B; C }] int +// +// In this example, the structural type restriction of P is ~string|int: A|B +// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, +// which when intersected with C (~string|~int) yields ~string|int. +// +// StructuralTerms computes these expansions and reductions, producing a +// "normalized" form of the embeddings. A structural restriction is normalized +// if it is a single union containing no interface terms, and is minimal in the +// sense that removing any term changes the set of types satisfying the +// constraint. It is left as a proof for the reader that, modulo sorting, there +// is exactly one such normalized form. +// +// Because the minimal representation always takes this form, StructuralTerms +// returns a slice of tilde terms corresponding to the terms of the union in +// the normalized structural restriction. An error is returned if the +// constraint interface is invalid, exceeds complexity bounds, or has an empty +// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet. +// +// StructuralTerms makes no guarantees about the order of terms, except that it +// is deterministic. +func StructuralTerms(tparam *TypeParam) ([]*Term, error) { + constraint := tparam.Constraint() + if constraint == nil { + return nil, fmt.Errorf("%s has nil constraint", tparam) + } + iface, _ := constraint.Underlying().(*types.Interface) + if iface == nil { + return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying()) + } + return InterfaceTermSet(iface) +} + +// InterfaceTermSet computes the normalized terms for a constraint interface, +// returning an error if the term set cannot be computed or is empty. In the +// latter case, the error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func InterfaceTermSet(iface *types.Interface) ([]*Term, error) { + return computeTermSet(iface) +} + +// UnionTermSet computes the normalized terms for a union, returning an error +// if the term set cannot be computed or is empty. In the latter case, the +// error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func UnionTermSet(union *Union) ([]*Term, error) { + return computeTermSet(union) +} + +func computeTermSet(typ types.Type) ([]*Term, error) { + tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) + if err != nil { + return nil, err + } + if tset.terms.isEmpty() { + return nil, ErrEmptyTypeSet + } + if tset.terms.isAll() { + return nil, nil + } + var terms []*Term + for _, term := range tset.terms { + terms = append(terms, NewTerm(term.tilde, term.typ)) + } + return terms, nil +} + +// A termSet holds the normalized set of terms for a given type. +// +// The name termSet is intentionally distinct from 'type set': a type set is +// all types that implement a type (and includes method restrictions), whereas +// a term set just represents the structural restrictions on a type. +type termSet struct { + complete bool + terms termlist +} + +func indentf(depth int, format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...) +} + +func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { + if t == nil { + panic("nil type") + } + + if debug { + indentf(depth, "%s", t.String()) + defer func() { + if err != nil { + indentf(depth, "=> %s", err) + } else { + indentf(depth, "=> %s", res.terms.String()) + } + }() + } + + const maxTermCount = 100 + if tset, ok := seen[t]; ok { + if !tset.complete { + return nil, fmt.Errorf("cycle detected in the declaration of %s", t) + } + return tset, nil + } + + // Mark the current type as seen to avoid infinite recursion. + tset := new(termSet) + defer func() { + tset.complete = true + }() + seen[t] = tset + + switch u := t.Underlying().(type) { + case *types.Interface: + // The term set of an interface is the intersection of the term sets of its + // embedded types. + tset.terms = allTermlist + for i := 0; i < u.NumEmbeddeds(); i++ { + embedded := u.EmbeddedType(i) + if _, ok := embedded.Underlying().(*TypeParam); ok { + return nil, fmt.Errorf("invalid embedded type %T", embedded) + } + tset2, err := computeTermSetInternal(embedded, seen, depth+1) + if err != nil { + return nil, err + } + tset.terms = tset.terms.intersect(tset2.terms) + } + case *Union: + // The term set of a union is the union of term sets of its terms. + tset.terms = nil + for i := 0; i < u.Len(); i++ { + t := u.Term(i) + var terms termlist + switch t.Type().Underlying().(type) { + case *types.Interface: + tset2, err := computeTermSetInternal(t.Type(), seen, depth+1) + if err != nil { + return nil, err + } + terms = tset2.terms + case *TypeParam, *Union: + // A stand-alone type parameter or union is not permitted as union + // term. + return nil, fmt.Errorf("invalid union term %T", t) + default: + if t.Type() == types.Typ[types.Invalid] { + continue + } + terms = termlist{{t.Tilde(), t.Type()}} + } + tset.terms = tset.terms.union(terms) + if len(tset.terms) > maxTermCount { + return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) + } + } + case *TypeParam: + panic("unreachable") + default: + // For all other types, the term set is just a single non-tilde term + // holding the type itself. + if u != types.Typ[types.Invalid] { + tset.terms = termlist{{false, t}} + } + } + return tset, nil +} + +// under is a facade for the go/types internal function of the same name. It is +// used by typeterm.go. +func under(t types.Type) types.Type { + return t.Underlying() +} diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/termlist.go b/libgo/go/golang.org/x/tools/internal/typeparams/termlist.go new file mode 100644 index 00000000000..10857d504c4 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/termlist.go @@ -0,0 +1,172 @@ +// Copyright 2021 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. + +// Code generated by copytermlist.go DO NOT EDIT. + +package typeparams + +import ( + "bytes" + "go/types" +) + +// A termlist represents the type set represented by the union +// t1 βͺ y2 βͺ ... tn of the type sets of the terms t1 to tn. +// A termlist is in normal form if all terms are disjoint. +// termlist operations don't require the operands to be in +// normal form. +type termlist []*term + +// allTermlist represents the set of all types. +// It is in normal form. +var allTermlist = termlist{new(term)} + +// String prints the termlist exactly (without normalization). +func (xl termlist) String() string { + if len(xl) == 0 { + return "β
" + } + var buf bytes.Buffer + for i, x := range xl { + if i > 0 { + buf.WriteString(" βͺ ") + } + buf.WriteString(x.String()) + } + return buf.String() +} + +// isEmpty reports whether the termlist xl represents the empty set of types. +func (xl termlist) isEmpty() bool { + // If there's a non-nil term, the entire list is not empty. + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil { + return false + } + } + return true +} + +// isAll reports whether the termlist xl represents the set of all types. +func (xl termlist) isAll() bool { + // If there's a π€ term, the entire list is π€. + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil && x.typ == nil { + return true + } + } + return false +} + +// norm returns the normal form of xl. +func (xl termlist) norm() termlist { + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + used := make([]bool, len(xl)) + var rl termlist + for i, xi := range xl { + if xi == nil || used[i] { + continue + } + for j := i + 1; j < len(xl); j++ { + xj := xl[j] + if xj == nil || used[j] { + continue + } + if u1, u2 := xi.union(xj); u2 == nil { + // If we encounter a π€ term, the entire list is π€. + // Exit early. + // (Note that this is not just an optimization; + // if we continue, we may end up with a π€ term + // and other terms and the result would not be + // in normal form.) + if u1.typ == nil { + return allTermlist + } + xi = u1 + used[j] = true // xj is now unioned into xi - ignore it in future iterations + } + } + rl = append(rl, xi) + } + return rl +} + +// If the type set represented by xl is specified by a single (non-π€) term, +// structuralType returns that type. Otherwise it returns nil. +func (xl termlist) structuralType() types.Type { + if nl := xl.norm(); len(nl) == 1 { + return nl[0].typ // if nl.isAll() then typ is nil, which is ok + } + return nil +} + +// union returns the union xl βͺ yl. +func (xl termlist) union(yl termlist) termlist { + return append(xl, yl...).norm() +} + +// intersect returns the intersection xl β© yl. +func (xl termlist) intersect(yl termlist) termlist { + if xl.isEmpty() || yl.isEmpty() { + return nil + } + + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + var rl termlist + for _, x := range xl { + for _, y := range yl { + if r := x.intersect(y); r != nil { + rl = append(rl, r) + } + } + } + return rl.norm() +} + +// equal reports whether xl and yl represent the same type set. +func (xl termlist) equal(yl termlist) bool { + // TODO(gri) this should be more efficient + return xl.subsetOf(yl) && yl.subsetOf(xl) +} + +// includes reports whether t β xl. +func (xl termlist) includes(t types.Type) bool { + for _, x := range xl { + if x.includes(t) { + return true + } + } + return false +} + +// supersetOf reports whether y β xl. +func (xl termlist) supersetOf(y *term) bool { + for _, x := range xl { + if y.subsetOf(x) { + return true + } + } + return false +} + +// subsetOf reports whether xl β yl. +func (xl termlist) subsetOf(yl termlist) bool { + if yl.isEmpty() { + return xl.isEmpty() + } + + // each term x of xl must be a subset of yl + for _, x := range xl { + if !yl.supersetOf(x) { + return false // x is not a subset yl + } + } + return true +} diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/typeparams_go117.go b/libgo/go/golang.org/x/tools/internal/typeparams/typeparams_go117.go new file mode 100644 index 00000000000..5fd3fc35156 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/typeparams_go117.go @@ -0,0 +1,192 @@ +// Copyright 2021 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. + +//go:build !go1.18 +// +build !go1.18 + +package typeparams + +import ( + "go/ast" + "go/token" + "go/types" +) + +func unsupported() { + panic("type parameters are unsupported at this go version") +} + +// IndexListExpr is a placeholder type, as type parameters are not supported at +// this Go version. Its methods panic on use. +type IndexListExpr struct { + ast.Expr + X ast.Expr // expression + Lbrack token.Pos // position of "[" + Indices []ast.Expr // index expressions + Rbrack token.Pos // position of "]" +} + +// ForTypeSpec returns an empty field list, as type parameters on not supported +// at this Go version. +func ForTypeSpec(*ast.TypeSpec) *ast.FieldList { + return nil +} + +// ForFuncType returns an empty field list, as type parameters are not +// supported at this Go version. +func ForFuncType(*ast.FuncType) *ast.FieldList { + return nil +} + +// TypeParam is a placeholder type, as type parameters are not supported at +// this Go version. Its methods panic on use. +type TypeParam struct{ types.Type } + +func (*TypeParam) Index() int { unsupported(); return 0 } +func (*TypeParam) Constraint() types.Type { unsupported(); return nil } +func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil } + +// TypeParamList is a placeholder for an empty type parameter list. +type TypeParamList struct{} + +func (*TypeParamList) Len() int { return 0 } +func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil } + +// TypeList is a placeholder for an empty type list. +type TypeList struct{} + +func (*TypeList) Len() int { return 0 } +func (*TypeList) At(int) types.Type { unsupported(); return nil } + +// NewTypeParam is unsupported at this Go version, and panics. +func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { + unsupported() + return nil +} + +// SetTypeParamConstraint is unsupported at this Go version, and panics. +func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { + unsupported() +} + +// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or +// typeParams is non-empty. +func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { + if len(recvTypeParams) != 0 || len(typeParams) != 0 { + panic("signatures cannot have type parameters at this Go version") + } + return types.NewSignature(recv, params, results, variadic) +} + +// ForSignature returns an empty slice. +func ForSignature(*types.Signature) *TypeParamList { + return nil +} + +// RecvTypeParams returns a nil slice. +func RecvTypeParams(sig *types.Signature) *TypeParamList { + return nil +} + +// IsComparable returns false, as no interfaces are type-restricted at this Go +// version. +func IsComparable(*types.Interface) bool { + return false +} + +// IsMethodSet returns true, as no interfaces are type-restricted at this Go +// version. +func IsMethodSet(*types.Interface) bool { + return true +} + +// IsImplicit returns false, as no interfaces are implicit at this Go version. +func IsImplicit(*types.Interface) bool { + return false +} + +// MarkImplicit does nothing, because this Go version does not have implicit +// interfaces. +func MarkImplicit(*types.Interface) {} + +// ForNamed returns an empty type parameter list, as type parameters are not +// supported at this Go version. +func ForNamed(*types.Named) *TypeParamList { + return nil +} + +// SetForNamed panics if tparams is non-empty. +func SetForNamed(_ *types.Named, tparams []*TypeParam) { + if len(tparams) > 0 { + unsupported() + } +} + +// NamedTypeArgs returns nil. +func NamedTypeArgs(*types.Named) *TypeList { + return nil +} + +// NamedTypeOrigin is the identity method at this Go version. +func NamedTypeOrigin(named *types.Named) types.Type { + return named +} + +// Term holds information about a structural type restriction. +type Term struct { + tilde bool + typ types.Type +} + +func (m *Term) Tilde() bool { return m.tilde } +func (m *Term) Type() types.Type { return m.typ } +func (m *Term) String() string { + pre := "" + if m.tilde { + pre = "~" + } + return pre + m.typ.String() +} + +// NewTerm is unsupported at this Go version, and panics. +func NewTerm(tilde bool, typ types.Type) *Term { + return &Term{tilde, typ} +} + +// Union is a placeholder type, as type parameters are not supported at this Go +// version. Its methods panic on use. +type Union struct{ types.Type } + +func (*Union) Len() int { return 0 } +func (*Union) Term(i int) *Term { unsupported(); return nil } + +// NewUnion is unsupported at this Go version, and panics. +func NewUnion(terms []*Term) *Union { + unsupported() + return nil +} + +// InitInstanceInfo is a noop at this Go version. +func InitInstanceInfo(*types.Info) {} + +// Instance is a placeholder type, as type parameters are not supported at this +// Go version. +type Instance struct { + TypeArgs *TypeList + Type types.Type +} + +// GetInstances returns a nil map, as type parameters are not supported at this +// Go version. +func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil } + +// Context is a placeholder type, as type parameters are not supported at +// this Go version. +type Context struct{} + +// Instantiate is unsupported on this Go version, and panics. +func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { + unsupported() + return nil, nil +} diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/typeparams_go118.go b/libgo/go/golang.org/x/tools/internal/typeparams/typeparams_go118.go new file mode 100644 index 00000000000..7470aed8c99 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/typeparams_go118.go @@ -0,0 +1,146 @@ +// Copyright 2021 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. + +//go:build go1.18 +// +build go1.18 + +package typeparams + +import ( + "go/ast" + "go/types" +) + +// IndexListExpr is an alias for ast.IndexListExpr. +type IndexListExpr = ast.IndexListExpr + +// ForTypeSpec returns n.TypeParams. +func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList { + if n == nil { + return nil + } + return n.TypeParams +} + +// ForFuncType returns n.TypeParams. +func ForFuncType(n *ast.FuncType) *ast.FieldList { + if n == nil { + return nil + } + return n.TypeParams +} + +// TypeParam is an alias for types.TypeParam +type TypeParam = types.TypeParam + +// TypeParamList is an alias for types.TypeParamList +type TypeParamList = types.TypeParamList + +// TypeList is an alias for types.TypeList +type TypeList = types.TypeList + +// NewTypeParam calls types.NewTypeParam. +func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { + return types.NewTypeParam(name, constraint) +} + +// SetTypeParamConstraint calls tparam.SetConstraint(constraint). +func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { + tparam.SetConstraint(constraint) +} + +// NewSignatureType calls types.NewSignatureType. +func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { + return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic) +} + +// ForSignature returns sig.TypeParams() +func ForSignature(sig *types.Signature) *TypeParamList { + return sig.TypeParams() +} + +// RecvTypeParams returns sig.RecvTypeParams(). +func RecvTypeParams(sig *types.Signature) *TypeParamList { + return sig.RecvTypeParams() +} + +// IsComparable calls iface.IsComparable(). +func IsComparable(iface *types.Interface) bool { + return iface.IsComparable() +} + +// IsMethodSet calls iface.IsMethodSet(). +func IsMethodSet(iface *types.Interface) bool { + return iface.IsMethodSet() +} + +// IsImplicit calls iface.IsImplicit(). +func IsImplicit(iface *types.Interface) bool { + return iface.IsImplicit() +} + +// MarkImplicit calls iface.MarkImplicit(). +func MarkImplicit(iface *types.Interface) { + iface.MarkImplicit() +} + +// ForNamed extracts the (possibly empty) type parameter object list from +// named. +func ForNamed(named *types.Named) *TypeParamList { + return named.TypeParams() +} + +// SetForNamed sets the type params tparams on n. Each tparam must be of +// dynamic type *types.TypeParam. +func SetForNamed(n *types.Named, tparams []*TypeParam) { + n.SetTypeParams(tparams) +} + +// NamedTypeArgs returns named.TypeArgs(). +func NamedTypeArgs(named *types.Named) *TypeList { + return named.TypeArgs() +} + +// NamedTypeOrigin returns named.Orig(). +func NamedTypeOrigin(named *types.Named) types.Type { + return named.Origin() +} + +// Term is an alias for types.Term. +type Term = types.Term + +// NewTerm calls types.NewTerm. +func NewTerm(tilde bool, typ types.Type) *Term { + return types.NewTerm(tilde, typ) +} + +// Union is an alias for types.Union +type Union = types.Union + +// NewUnion calls types.NewUnion. +func NewUnion(terms []*Term) *Union { + return types.NewUnion(terms) +} + +// InitInstanceInfo initializes info to record information about type and +// function instances. +func InitInstanceInfo(info *types.Info) { + info.Instances = make(map[*ast.Ident]types.Instance) +} + +// Instance is an alias for types.Instance. +type Instance = types.Instance + +// GetInstances returns info.Instances. +func GetInstances(info *types.Info) map[*ast.Ident]Instance { + return info.Instances +} + +// Context is an alias for types.Context. +type Context = types.Context + +// Instantiate calls types.Instantiate. +func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { + return types.Instantiate(ctxt, typ, targs, validate) +} diff --git a/libgo/go/golang.org/x/tools/internal/typeparams/typeterm.go b/libgo/go/golang.org/x/tools/internal/typeparams/typeterm.go new file mode 100644 index 00000000000..7ddee28d987 --- /dev/null +++ b/libgo/go/golang.org/x/tools/internal/typeparams/typeterm.go @@ -0,0 +1,170 @@ +// Copyright 2021 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. + +// Code generated by copytermlist.go DO NOT EDIT. + +package typeparams + +import "go/types" + +// A term describes elementary type sets: +// +// β
: (*term)(nil) == β
// set of no types (empty set) +// π€: &term{} == π€ // set of all types (π€niverse) +// T: &term{false, T} == {T} // set of type T +// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t +// +type term struct { + tilde bool // valid if typ != nil + typ types.Type +} + +func (x *term) String() string { + switch { + case x == nil: + return "β
" + case x.typ == nil: + return "π€" + case x.tilde: + return "~" + x.typ.String() + default: + return x.typ.String() + } +} + +// equal reports whether x and y represent the same type set. +func (x *term) equal(y *term) bool { + // easy cases + switch { + case x == nil || y == nil: + return x == y + case x.typ == nil || y.typ == nil: + return x.typ == y.typ + } + // β
β x, y β π€ + + return x.tilde == y.tilde && types.Identical(x.typ, y.typ) +} + +// union returns the union x βͺ y: zero, one, or two non-nil terms. +func (x *term) union(y *term) (_, _ *term) { + // easy cases + switch { + case x == nil && y == nil: + return nil, nil // β
βͺ β
== β
+ case x == nil: + return y, nil // β
βͺ y == y + case y == nil: + return x, nil // x βͺ β
== x + case x.typ == nil: + return x, nil // π€ βͺ y == π€ + case y.typ == nil: + return y, nil // x βͺ π€ == π€ + } + // β
β x, y β π€ + + if x.disjoint(y) { + return x, y // x βͺ y == (x, y) if x β© y == β
+ } + // x.typ == y.typ + + // ~t βͺ ~t == ~t + // ~t βͺ T == ~t + // T βͺ ~t == ~t + // T βͺ T == T + if x.tilde || !y.tilde { + return x, nil + } + return y, nil +} + +// intersect returns the intersection x β© y. +func (x *term) intersect(y *term) *term { + // easy cases + switch { + case x == nil || y == nil: + return nil // β
β© y == β
and β© β
== β
+ case x.typ == nil: + return y // π€ β© y == y + case y.typ == nil: + return x // x β© π€ == x + } + // β
β x, y β π€ + + if x.disjoint(y) { + return nil // x β© y == β
if x β© y == β
+ } + // x.typ == y.typ + + // ~t β© ~t == ~t + // ~t β© T == T + // T β© ~t == T + // T β© T == T + if !x.tilde || y.tilde { + return x + } + return y +} + +// includes reports whether t β x. +func (x *term) includes(t types.Type) bool { + // easy cases + switch { + case x == nil: + return false // t β β
== false + case x.typ == nil: + return true // t β π€ == true + } + // β
β x β π€ + + u := t + if x.tilde { + u = under(u) + } + return types.Identical(x.typ, u) +} + +// subsetOf reports whether x β y. +func (x *term) subsetOf(y *term) bool { + // easy cases + switch { + case x == nil: + return true // β
β y == true + case y == nil: + return false // x β β
== false since x != β
+ case y.typ == nil: + return true // x β π€ == true + case x.typ == nil: + return false // π€ β y == false since y != π€ + } + // β
β x, y β π€ + + if x.disjoint(y) { + return false // x β y == false if x β© y == β
+ } + // x.typ == y.typ + + // ~t β ~t == true + // ~t β T == false + // T β ~t == true + // T β T == true + return !x.tilde || y.tilde +} + +// disjoint reports whether x β© y == β
. +// x.typ and y.typ must not be nil. +func (x *term) disjoint(y *term) bool { + if debug && (x.typ == nil || y.typ == nil) { + panic("invalid argument(s)") + } + ux := x.typ + if y.tilde { + ux = under(ux) + } + uy := y.typ + if x.tilde { + uy = under(uy) + } + return !types.Identical(ux, uy) +} diff --git a/libgo/go/golang.org/x/tools/txtar/archive.go b/libgo/go/golang.org/x/tools/txtar/archive.go new file mode 100644 index 00000000000..214256617b5 --- /dev/null +++ b/libgo/go/golang.org/x/tools/txtar/archive.go @@ -0,0 +1,140 @@ +// Copyright 2018 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 txtar implements a trivial text-based file archive format. +// +// The goals for the format are: +// +// - be trivial enough to create and edit by hand. +// - be able to store trees of text files describing go command test cases. +// - diff nicely in git history and code reviews. +// +// Non-goals include being a completely general archive format, +// storing binary data, storing file modes, storing special files like +// symbolic links, and so on. +// +// Txtar format +// +// A txtar archive is zero or more comment lines and then a sequence of file entries. +// Each file entry begins with a file marker line of the form "-- FILENAME --" +// and is followed by zero or more file content lines making up the file data. +// The comment or file content ends at the next file marker line. +// The file marker line must begin with the three-byte sequence "-- " +// and end with the three-byte sequence " --", but the enclosed +// file name can be surrounding by additional white space, +// all of which is stripped. +// +// If the txtar file is missing a trailing newline on the final line, +// parsers should consider a final newline to be present anyway. +// +// There are no possible syntax errors in a txtar archive. +package txtar + +import ( + "bytes" + "fmt" + "io/ioutil" + "strings" +) + +// An Archive is a collection of files. +type Archive struct { + Comment []byte + Files []File +} + +// A File is a single file in an archive. +type File struct { + Name string // name of file ("foo/bar.txt") + Data []byte // text content of file +} + +// Format returns the serialized form of an Archive. +// It is assumed that the Archive data structure is well-formed: +// a.Comment and all a.File[i].Data contain no file marker lines, +// and all a.File[i].Name is non-empty. +func Format(a *Archive) []byte { + var buf bytes.Buffer + buf.Write(fixNL(a.Comment)) + for _, f := range a.Files { + fmt.Fprintf(&buf, "-- %s --\n", f.Name) + buf.Write(fixNL(f.Data)) + } + return buf.Bytes() +} + +// ParseFile parses the named file as an archive. +func ParseFile(file string) (*Archive, error) { + data, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + return Parse(data), nil +} + +// Parse parses the serialized form of an Archive. +// The returned Archive holds slices of data. +func Parse(data []byte) *Archive { + a := new(Archive) + var name string + a.Comment, name, data = findFileMarker(data) + for name != "" { + f := File{name, nil} + f.Data, name, data = findFileMarker(data) + a.Files = append(a.Files, f) + } + return a +} + +var ( + newlineMarker = []byte("\n-- ") + marker = []byte("-- ") + markerEnd = []byte(" --") +) + +// findFileMarker finds the next file marker in data, +// extracts the file name, and returns the data before the marker, +// the file name, and the data after the marker. +// If there is no next marker, findFileMarker returns before = fixNL(data), name = "", after = nil. +func findFileMarker(data []byte) (before []byte, name string, after []byte) { + var i int + for { + if name, after = isMarker(data[i:]); name != "" { + return data[:i], name, after + } + j := bytes.Index(data[i:], newlineMarker) + if j < 0 { + return fixNL(data), "", nil + } + i += j + 1 // positioned at start of new possible marker + } +} + +// isMarker checks whether data begins with a file marker line. +// If so, it returns the name from the line and the data after the line. +// Otherwise it returns name == "" with an unspecified after. +func isMarker(data []byte) (name string, after []byte) { + if !bytes.HasPrefix(data, marker) { + return "", nil + } + if i := bytes.IndexByte(data, '\n'); i >= 0 { + data, after = data[:i], data[i+1:] + } + if !(bytes.HasSuffix(data, markerEnd) && len(data) >= len(marker)+len(markerEnd)) { + return "", nil + } + return strings.TrimSpace(string(data[len(marker) : len(data)-len(markerEnd)])), after +} + +// If data is empty or ends in \n, fixNL returns data. +// Otherwise fixNL returns a new slice consisting of data with a final \n added. +func fixNL(data []byte) []byte { + if len(data) == 0 || data[len(data)-1] == '\n' { + return data + } + d := make([]byte, len(data)+1) + copy(d, data) + d[len(data)] = '\n' + return d +} |