diff --git a/compiler/natives/src/crypto/elliptic/nistec.go b/compiler/natives/src/crypto/elliptic/nistec.go deleted file mode 100644 index 326c602d5..000000000 --- a/compiler/natives/src/crypto/elliptic/nistec.go +++ /dev/null @@ -1,81 +0,0 @@ -//go:build js -// +build js - -package elliptic - -import ( - "crypto/internal/nistec" - "math/big" -) - -// nistPoint uses generics so must be removed for generic-less GopherJS. -// All the following code changes in this file are to make p224, p256, -// p521, and p384 still function correctly without this generic struct. -// -//gopherjs:purge for go1.19 without generics -type nistPoint[T any] interface{} - -// nistCurve replaces the generics with a version using the wrappedPoint -// interface, then update all the method signatures to also use wrappedPoint. -type nistCurve struct { - newPoint func() nistec.WrappedPoint - params *CurveParams -} - -//gopherjs:override-signature -func (curve *nistCurve) Params() *CurveParams - -//gopherjs:override-signature -func (curve *nistCurve) IsOnCurve(x, y *big.Int) bool - -//gopherjs:override-signature -func (curve *nistCurve) pointFromAffine(x, y *big.Int) (p nistec.WrappedPoint, err error) - -//gopherjs:override-signature -func (curve *nistCurve) pointToAffine(p nistec.WrappedPoint) (x, y *big.Int) - -//gopherjs:override-signature -func (curve *nistCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) - -//gopherjs:override-signature -func (curve *nistCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) - -//gopherjs:override-signature -func (curve *nistCurve) normalizeScalar(scalar []byte) []byte - -//gopherjs:override-signature -func (curve *nistCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) - -//gopherjs:override-signature -func (curve *nistCurve) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) - -//gopherjs:override-signature -func (curve *nistCurve) CombinedMult(Px, Py *big.Int, s1, s2 []byte) (x, y *big.Int) - -//gopherjs:override-signature -func (curve *nistCurve) Unmarshal(data []byte) (x, y *big.Int) - -//gopherjs:override-signature -func (curve *nistCurve) UnmarshalCompressed(data []byte) (x, y *big.Int) - -var p224 = &nistCurve{ - newPoint: nistec.NewP224WrappedPoint, -} - -type p256Curve struct { - nistCurve -} - -var p256 = &p256Curve{ - nistCurve: nistCurve{ - newPoint: nistec.NewP256WrappedPoint, - }, -} - -var p521 = &nistCurve{ - newPoint: nistec.NewP521WrappedPoint, -} - -var p384 = &nistCurve{ - newPoint: nistec.NewP384WrappedPoint, -} diff --git a/compiler/natives/src/crypto/internal/nistec/nistec_test.go b/compiler/natives/src/crypto/internal/nistec/nistec_test.go deleted file mode 100644 index d755e7ec3..000000000 --- a/compiler/natives/src/crypto/internal/nistec/nistec_test.go +++ /dev/null @@ -1,89 +0,0 @@ -//go:build js -// +build js - -package nistec_test - -import ( - "crypto/elliptic" - "crypto/internal/nistec" - "testing" -) - -func TestAllocations(t *testing.T) { - t.Skip("testing.AllocsPerRun not supported in GopherJS") -} - -//gopherjs:purge -type nistPoint[T any] interface{} - -func TestEquivalents(t *testing.T) { - t.Run("P224", func(t *testing.T) { - testEquivalents(t, nistec.NewP224WrappedPoint, nistec.NewP224WrappedGenerator, elliptic.P224()) - }) - t.Run("P256", func(t *testing.T) { - testEquivalents(t, nistec.NewP256WrappedPoint, nistec.NewP256WrappedGenerator, elliptic.P256()) - }) - t.Run("P384", func(t *testing.T) { - testEquivalents(t, nistec.NewP384WrappedPoint, nistec.NewP384WrappedGenerator, elliptic.P384()) - }) - t.Run("P521", func(t *testing.T) { - testEquivalents(t, nistec.NewP521WrappedPoint, nistec.NewP521WrappedGenerator, elliptic.P521()) - }) -} - -//gopherjs:override-signature -func testEquivalents(t *testing.T, newPoint, newGenerator func() nistec.WrappedPoint, c elliptic.Curve) - -func TestScalarMult(t *testing.T) { - t.Run("P224", func(t *testing.T) { - testScalarMult(t, nistec.NewP224WrappedPoint, nistec.NewP224WrappedGenerator, elliptic.P224()) - }) - t.Run("P256", func(t *testing.T) { - testScalarMult(t, nistec.NewP256WrappedPoint, nistec.NewP256WrappedGenerator, elliptic.P256()) - }) - t.Run("P384", func(t *testing.T) { - testScalarMult(t, nistec.NewP384WrappedPoint, nistec.NewP384WrappedGenerator, elliptic.P384()) - }) - t.Run("P521", func(t *testing.T) { - testScalarMult(t, nistec.NewP521WrappedPoint, nistec.NewP521WrappedGenerator, elliptic.P521()) - }) -} - -//gopherjs:override-signature -func testScalarMult(t *testing.T, newPoint, newGenerator func() nistec.WrappedPoint, c elliptic.Curve) - -func BenchmarkScalarMult(b *testing.B) { - b.Run("P224", func(b *testing.B) { - benchmarkScalarMult(b, nistec.NewP224WrappedGenerator(), 28) - }) - b.Run("P256", func(b *testing.B) { - benchmarkScalarMult(b, nistec.NewP256WrappedGenerator(), 32) - }) - b.Run("P384", func(b *testing.B) { - benchmarkScalarMult(b, nistec.NewP384WrappedGenerator(), 48) - }) - b.Run("P521", func(b *testing.B) { - benchmarkScalarMult(b, nistec.NewP521WrappedGenerator(), 66) - }) -} - -//gopherjs:override-signature -func benchmarkScalarMult(b *testing.B, p nistec.WrappedPoint, scalarSize int) - -func BenchmarkScalarBaseMult(b *testing.B) { - b.Run("P224", func(b *testing.B) { - benchmarkScalarBaseMult(b, nistec.NewP224WrappedGenerator(), 28) - }) - b.Run("P256", func(b *testing.B) { - benchmarkScalarBaseMult(b, nistec.NewP256WrappedGenerator(), 32) - }) - b.Run("P384", func(b *testing.B) { - benchmarkScalarBaseMult(b, nistec.NewP384WrappedGenerator(), 48) - }) - b.Run("P521", func(b *testing.B) { - benchmarkScalarBaseMult(b, nistec.NewP521WrappedGenerator(), 66) - }) -} - -//gopherjs:override-signature -func benchmarkScalarBaseMult(b *testing.B, p nistec.WrappedPoint, scalarSize int) diff --git a/compiler/natives/src/crypto/internal/nistec/wrapper.go b/compiler/natives/src/crypto/internal/nistec/wrapper.go deleted file mode 100644 index 0d6706b52..000000000 --- a/compiler/natives/src/crypto/internal/nistec/wrapper.go +++ /dev/null @@ -1,185 +0,0 @@ -//go:build js -// +build js - -package nistec - -type WrappedPoint interface { - Bytes() []byte - SetBytes(b []byte) (WrappedPoint, error) - Add(w1, w2 WrappedPoint) WrappedPoint - Double(w1 WrappedPoint) WrappedPoint - ScalarMult(w1 WrappedPoint, scalar []byte) (WrappedPoint, error) - ScalarBaseMult(scalar []byte) (WrappedPoint, error) -} - -type p224Wrapper struct { - point *P224Point -} - -func wrapP224(point *P224Point) WrappedPoint { - return p224Wrapper{point: point} -} - -func NewP224WrappedPoint() WrappedPoint { - return wrapP224(NewP224Point()) -} - -func NewP224WrappedGenerator() WrappedPoint { - return wrapP224(NewP224Generator()) -} - -func (w p224Wrapper) Bytes() []byte { - return w.point.Bytes() -} - -func (w p224Wrapper) SetBytes(b []byte) (WrappedPoint, error) { - p, err := w.point.SetBytes(b) - return wrapP224(p), err -} - -func (w p224Wrapper) Add(w1, w2 WrappedPoint) WrappedPoint { - return wrapP224(w.point.Add(w1.(p224Wrapper).point, w2.(p224Wrapper).point)) -} - -func (w p224Wrapper) Double(w1 WrappedPoint) WrappedPoint { - return wrapP224(w.point.Double(w1.(p224Wrapper).point)) -} - -func (w p224Wrapper) ScalarMult(w1 WrappedPoint, scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarMult(w1.(p224Wrapper).point, scalar) - return wrapP224(p), err -} - -func (w p224Wrapper) ScalarBaseMult(scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarBaseMult(scalar) - return wrapP224(p), err -} - -type p256Wrapper struct { - point *P256Point -} - -func wrapP256(point *P256Point) WrappedPoint { - return p256Wrapper{point: point} -} - -func NewP256WrappedPoint() WrappedPoint { - return wrapP256(NewP256Point()) -} - -func NewP256WrappedGenerator() WrappedPoint { - return wrapP256(NewP256Generator()) -} - -func (w p256Wrapper) Bytes() []byte { - return w.point.Bytes() -} - -func (w p256Wrapper) SetBytes(b []byte) (WrappedPoint, error) { - p, err := w.point.SetBytes(b) - return wrapP256(p), err -} - -func (w p256Wrapper) Add(w1, w2 WrappedPoint) WrappedPoint { - return wrapP256(w.point.Add(w1.(p256Wrapper).point, w2.(p256Wrapper).point)) -} - -func (w p256Wrapper) Double(w1 WrappedPoint) WrappedPoint { - return wrapP256(w.point.Double(w1.(p256Wrapper).point)) -} - -func (w p256Wrapper) ScalarMult(w1 WrappedPoint, scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarMult(w1.(p256Wrapper).point, scalar) - return wrapP256(p), err -} - -func (w p256Wrapper) ScalarBaseMult(scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarBaseMult(scalar) - return wrapP256(p), err -} - -type p521Wrapper struct { - point *P521Point -} - -func wrapP521(point *P521Point) WrappedPoint { - return p521Wrapper{point: point} -} - -func NewP521WrappedPoint() WrappedPoint { - return wrapP521(NewP521Point()) -} - -func NewP521WrappedGenerator() WrappedPoint { - return wrapP521(NewP521Generator()) -} - -func (w p521Wrapper) Bytes() []byte { - return w.point.Bytes() -} - -func (w p521Wrapper) SetBytes(b []byte) (WrappedPoint, error) { - p, err := w.point.SetBytes(b) - return wrapP521(p), err -} - -func (w p521Wrapper) Add(w1, w2 WrappedPoint) WrappedPoint { - return wrapP521(w.point.Add(w1.(p521Wrapper).point, w2.(p521Wrapper).point)) -} - -func (w p521Wrapper) Double(w1 WrappedPoint) WrappedPoint { - return wrapP521(w.point.Double(w1.(p521Wrapper).point)) -} - -func (w p521Wrapper) ScalarMult(w1 WrappedPoint, scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarMult(w1.(p521Wrapper).point, scalar) - return wrapP521(p), err -} - -func (w p521Wrapper) ScalarBaseMult(scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarBaseMult(scalar) - return wrapP521(p), err -} - -type p384Wrapper struct { - point *P384Point -} - -func wrapP384(point *P384Point) WrappedPoint { - return p384Wrapper{point: point} -} - -func NewP384WrappedPoint() WrappedPoint { - return wrapP384(NewP384Point()) -} - -func NewP384WrappedGenerator() WrappedPoint { - return wrapP384(NewP384Generator()) -} - -func (w p384Wrapper) Bytes() []byte { - return w.point.Bytes() -} - -func (w p384Wrapper) SetBytes(b []byte) (WrappedPoint, error) { - p, err := w.point.SetBytes(b) - return wrapP384(p), err -} - -func (w p384Wrapper) Add(w1, w2 WrappedPoint) WrappedPoint { - return wrapP384(w.point.Add(w1.(p384Wrapper).point, w2.(p384Wrapper).point)) -} - -func (w p384Wrapper) Double(w1 WrappedPoint) WrappedPoint { - return wrapP384(w.point.Double(w1.(p384Wrapper).point)) -} - -func (w p384Wrapper) ScalarMult(w1 WrappedPoint, scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarMult(w1.(p384Wrapper).point, scalar) - return wrapP384(p), err -} - -func (w p384Wrapper) ScalarBaseMult(scalar []byte) (WrappedPoint, error) { - p, err := w.point.ScalarBaseMult(scalar) - return wrapP384(p), err -} diff --git a/compiler/natives/src/go/token/position.go b/compiler/natives/src/go/token/position.go deleted file mode 100644 index 6a1ee0c15..000000000 --- a/compiler/natives/src/go/token/position.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build js -// +build js - -package token - -import "sync" - -type FileSet struct { - mutex sync.RWMutex - base int - files []*File - - // replaced atomic.Pointer[File] for go1.19 without generics. - last atomicFilePointer -} - -type atomicFilePointer struct { - v *File -} - -func (x *atomicFilePointer) Load() *File { return x.v } -func (x *atomicFilePointer) Store(val *File) { x.v = val } diff --git a/compiler/natives/src/internal/reflectlite/all_test.go b/compiler/natives/src/internal/reflectlite/all_test.go index 4445189a0..977438e4e 100644 --- a/compiler/natives/src/internal/reflectlite/all_test.go +++ b/compiler/natives/src/internal/reflectlite/all_test.go @@ -21,27 +21,3 @@ func TestTypes(t *testing.T) { func TestNameBytesAreAligned(t *testing.T) { t.Skip("TestNameBytesAreAligned") } - -// `A` is used with `B[T any]` and is otherwise not needed. -// -//gopherjs:purge for go1.19 without generics -type ( - A struct{} - B[T any] struct{} -) - -// removing the name tests using `B[T any]` for go1.19 without generics -var nameTests = []nameTest{ - {(*int32)(nil), "int32"}, - {(*D1)(nil), "D1"}, - {(*[]D1)(nil), ""}, - {(*chan D1)(nil), ""}, - {(*func() D1)(nil), ""}, - {(*<-chan D1)(nil), ""}, - {(*chan<- D1)(nil), ""}, - {(*any)(nil), ""}, - {(*interface { - F() - })(nil), ""}, - {(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"}, -} diff --git a/compiler/natives/src/reflect/reflect_test.go b/compiler/natives/src/reflect/reflect_test.go index 79bbe5385..c18acc614 100644 --- a/compiler/natives/src/reflect/reflect_test.go +++ b/compiler/natives/src/reflect/reflect_test.go @@ -285,16 +285,6 @@ func TestMethodCallValueCodePtr(t *testing.T) { t.Skip("methodValueCallCodePtr() is not applicable in GopherJS") } -//gopherjs:purge for go1.19 without generics -type ( - A struct{} - B[T any] struct{} -) - -func TestIssue50208(t *testing.T) { - t.Skip("This test required generics, which are not yet supported: https://github.com/gopherjs/gopherjs/issues/1013") -} - func TestStructOfTooLarge(t *testing.T) { t.Skip("This test is dependent on field alignment to determine if a struct size would exceed virtual address space.") } diff --git a/compiler/natives/src/sync/atomic/atomic.go b/compiler/natives/src/sync/atomic/atomic.go index 1cbfe65f9..ebc98e910 100644 --- a/compiler/natives/src/sync/atomic/atomic.go +++ b/compiler/natives/src/sync/atomic/atomic.go @@ -220,6 +220,3 @@ func sameType(x, y interface{}) bool { // existing and differing for different types. return js.InternalObject(x).Get("constructor") == js.InternalObject(y).Get("constructor") } - -//gopherjs:purge for go1.19 without generics -type Pointer[T any] struct{} diff --git a/compiler/natives/src/sync/atomic/atomic_test.go b/compiler/natives/src/sync/atomic/atomic_test.go index e1ec6086c..223f35989 100644 --- a/compiler/natives/src/sync/atomic/atomic_test.go +++ b/compiler/natives/src/sync/atomic/atomic_test.go @@ -3,51 +3,7 @@ package atomic_test -import ( - "testing" - "unsafe" -) - -//gopherjs:purge for go1.19 without generics -func testPointers() []unsafe.Pointer {} - -func TestSwapPointer(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -func TestSwapPointerMethod(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -func TestCompareAndSwapPointer(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -func TestCompareAndSwapPointerMethod(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -func TestLoadPointer(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -func TestLoadPointerMethod(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -func TestStorePointer(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -func TestStorePointerMethod(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -//gopherjs:purge for go1.19 without generics -func hammerStoreLoadPointer(t *testing.T, paddr unsafe.Pointer) {} - -//gopherjs:purge for go1.19 without generics -func hammerStoreLoadPointerMethod(t *testing.T, paddr unsafe.Pointer) {} +import "testing" func TestHammerStoreLoad(t *testing.T) { t.Skip("use of unsafe") @@ -61,13 +17,6 @@ func TestAutoAligned64(t *testing.T) { t.Skip("GopherJS emulates atomics, which makes alignment irrelevant.") } -func TestNilDeref(t *testing.T) { - t.Skip("GopherJS does not support generics yet.") -} - -//gopherjs:purge for go1.19 without generics -type List struct{} - func TestHammer32(t *testing.T) { t.Skip("use of unsafe") } diff --git a/compiler/natives/src/sync/map.go b/compiler/natives/src/sync/map.go index 3f81b9b31..44973bba0 100644 --- a/compiler/natives/src/sync/map.go +++ b/compiler/natives/src/sync/map.go @@ -6,7 +6,13 @@ package sync type Map struct { mu Mutex - // replaced atomic.Pointer[readOnly] for go1.20 without generics. + // TODO(grantnelson-wf): Remove this override after generics are supported. + // https://github.com/gopherjs/gopherjs/issues/1013. + // + // This override is still needed with initial generics support because otherwise we get: + // [compiler panic] unexpected compiler panic while building package "reflect": + // requesting ID of instance {type sync/atomic.Pointer[T any] struct{_ [0]*T; _ sync/atomic.noCopy; v unsafe.Pointer} sync.readOnly} + // that hasn't been added to the set read atomicReadOnlyPointer dirty map[any]*entry @@ -19,30 +25,3 @@ type atomicReadOnlyPointer struct { func (x *atomicReadOnlyPointer) Load() *readOnly { return x.v } func (x *atomicReadOnlyPointer) Store(val *readOnly) { x.v = val } - -type entry struct { - - // replaced atomic.Pointer[any] for go1.20 without generics. - p atomicAnyPointer -} - -type atomicAnyPointer struct { - v *any -} - -func (x *atomicAnyPointer) Load() *any { return x.v } -func (x *atomicAnyPointer) Store(val *any) { x.v = val } - -func (x *atomicAnyPointer) Swap(new *any) *any { - old := x.v - x.v = new - return old -} - -func (x *atomicAnyPointer) CompareAndSwap(old, new *any) bool { - if x.v == old { - x.v = new - return true - } - return false -} diff --git a/compiler/natives/src/testing/helper_test.go b/compiler/natives/src/testing/helper_test.go deleted file mode 100644 index 6815fd651..000000000 --- a/compiler/natives/src/testing/helper_test.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build js -// +build js - -package testing - -func TestTBHelper(t *T) { - t.Skip("GopherJS does not support generics yet.") -} diff --git a/compiler/natives/src/testing/helperfuncs_test.go b/compiler/natives/src/testing/helperfuncs_test.go deleted file mode 100644 index 54a1ee737..000000000 --- a/compiler/natives/src/testing/helperfuncs_test.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build js -// +build js - -package testing - -//gopherjs:purge for go1.19 without generics -func genericHelper[G any](t *T, msg string) - -//gopherjs:purge for go1.19 without generics -var genericIntHelper = genericHelper[int] - -//gopherjs:purge for go1.19 without generics (uses genericHelper) -func testHelper(t *T) diff --git a/compiler/natives/src/time/format.go b/compiler/natives/src/time/format.go deleted file mode 100644 index 0e1594c19..000000000 --- a/compiler/natives/src/time/format.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build js -// +build js - -package time - -// copied and replaced for go1.20 temporarily without generics. -func atoi(sAny any) (x int, err error) { - s := asBytes(sAny) - neg := false - if len(s) > 0 && (s[0] == '-' || s[0] == '+') { - neg = s[0] == '-' - s = s[1:] - } - q, remStr, err := leadingInt(s) - rem := []byte(remStr) - x = int(q) - if err != nil || len(rem) > 0 { - return 0, atoiError - } - if neg { - x = -x - } - return x, nil -} - -// copied and replaced for go1.20 temporarily without generics. -func isDigit(sAny any, i int) bool { - s := asBytes(sAny) - if len(s) <= i { - return false - } - c := s[i] - return '0' <= c && c <= '9' -} - -// copied and replaced for go1.20 temporarily without generics. -func parseNanoseconds(sAny any, nbytes int) (ns int, rangeErrString string, err error) { - value := asBytes(sAny) - if !commaOrPeriod(value[0]) { - err = errBad - return - } - if nbytes > 10 { - value = value[:10] - nbytes = 10 - } - if ns, err = atoi(value[1:nbytes]); err != nil { - return - } - if ns < 0 { - rangeErrString = "fractional second" - return - } - scaleDigits := 10 - nbytes - for i := 0; i < scaleDigits; i++ { - ns *= 10 - } - return -} - -// copied and replaced for go1.20 temporarily without generics. -func leadingInt(sAny any) (x uint64, rem string, err error) { - s := asBytes(sAny) - i := 0 - for ; i < len(s); i++ { - c := s[i] - if c < '0' || c > '9' { - break - } - if x > 1<<63/10 { - return 0, rem, errLeadingInt - } - x = x*10 + uint64(c) - '0' - if x > 1<<63 { - return 0, rem, errLeadingInt - } - } - return x, string(s[i:]), nil -} diff --git a/compiler/natives/src/time/format_rfc3339.go b/compiler/natives/src/time/format_rfc3339.go deleted file mode 100644 index 7c69bfc95..000000000 --- a/compiler/natives/src/time/format_rfc3339.go +++ /dev/null @@ -1,85 +0,0 @@ -//go:build js -// +build js - -package time - -import "errors" - -// added for go1.20 temporarily without generics. -func asBytes(s any) []byte { - switch t := s.(type) { - case []byte: - return t - case string: - return []byte(t) - default: - panic(errors.New(`unexpected type passed to asBytes, expected string or []bytes`)) - } -} - -// copied and replaced for go1.20 temporarily without generics. -func parseRFC3339(sAny any, local *Location) (Time, bool) { - s := asBytes(sAny) - ok := true - parseUint := func(s []byte, min, max int) (x int) { - for _, c := range s { - if c < '0' || '9' < c { - ok = false - return min - } - x = x*10 + int(c) - '0' - } - if x < min || max < x { - ok = false - return min - } - return x - } - - if len(s) < len("2006-01-02T15:04:05") { - return Time{}, false - } - year := parseUint(s[0:4], 0, 9999) - month := parseUint(s[5:7], 1, 12) - day := parseUint(s[8:10], 1, daysIn(Month(month), year)) - hour := parseUint(s[11:13], 0, 23) - min := parseUint(s[14:16], 0, 59) - sec := parseUint(s[17:19], 0, 59) - if !ok || !(s[4] == '-' && s[7] == '-' && s[10] == 'T' && s[13] == ':' && s[16] == ':') { - return Time{}, false - } - s = s[19:] - - var nsec int - if len(s) >= 2 && s[0] == '.' && isDigit(s, 1) { - n := 2 - for ; n < len(s) && isDigit(s, n); n++ { - } - nsec, _, _ = parseNanoseconds(s, n) - s = s[n:] - } - - t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) - if len(s) != 1 || s[0] != 'Z' { - if len(s) != len("-07:00") { - return Time{}, false - } - hr := parseUint(s[1:3], 0, 23) - mm := parseUint(s[4:6], 0, 59) - if !ok || !((s[0] == '-' || s[0] == '+') && s[3] == ':') { - return Time{}, false - } - zoneOffset := (hr*60 + mm) * 60 - if s[0] == '-' { - zoneOffset *= -1 - } - t.addSec(-int64(zoneOffset)) - - if _, offset, _, _, _ := local.lookup(t.unixSec()); offset == zoneOffset { - t.setLoc(local) - } else { - t.setLoc(FixedZone("", zoneOffset)) - } - } - return t, true -}