From e5ba86c391ac466d6e86be2d1310949a5a3eb527 Mon Sep 17 00:00:00 2001 From: gdziadkiewicz Date: Sat, 15 Jun 2019 15:31:11 +0200 Subject: [PATCH] Fix #5729 --- src/fsharp/FSharp.Core/prim-types.fs | 28 +++++---- src/fsharp/lex.fsl | 14 ++--- .../FSharp.Core/PrimTypes.fs | 58 ++++++++++++++++++- .../NumericLiterals/E_MaxLiterals04.fs | 11 ++++ .../LexicalAnalysis/NumericLiterals/env.lst | 1 + 5 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/E_MaxLiterals04.fs diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs index 2e91dec124f8..bfd5bdacc9f0 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -2395,13 +2395,11 @@ namespace Microsoft.FSharp.Core then p <- p + 1; -1L else 1L - let parseOctalUInt64 (s:string) p l = - let rec parse n acc = if n < l then parse (n+1) (acc *.. 8UL +.. (let c = s.Chars(n) in if c >=... '0' && c <=... '7' then Convert.ToUInt64(c) -.. Convert.ToUInt64('0') else formatError())) else acc in - parse p 0UL - - let parseBinaryUInt64 (s:string) p l = - let rec parse n acc = if n < l then parse (n+1) (acc *.. 2UL +.. (match s.Chars(n) with '0' -> 0UL | '1' -> 1UL | _ -> formatError())) else acc in - parse p 0UL + let parseBinaryUInt64 (s:string) = + Convert.ToUInt64(s, 2) + + let parseOctalUInt64 (s:string) = + Convert.ToUInt64(s, 8) let inline removeUnderscores (s:string) = match s with @@ -2418,8 +2416,8 @@ namespace Microsoft.FSharp.Core if p >= l then formatError() else match specifier with | 'x' -> UInt32.Parse( s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture) - | 'b' -> Convert.ToUInt32(parseBinaryUInt64 s p l) - | 'o' -> Convert.ToUInt32(parseOctalUInt64 s p l) + | 'b' -> Convert.ToUInt32(parseBinaryUInt64 (s.Substring(p))) + | 'o' -> Convert.ToUInt32(parseOctalUInt64 (s.Substring(p))) | _ -> UInt32.Parse(s.Substring(p), NumberStyles.Integer, CultureInfo.InvariantCulture) in let inline int32OfUInt32 (x:uint32) = (# "" x : int32 #) @@ -2436,8 +2434,8 @@ namespace Microsoft.FSharp.Core if p >= l then formatError() else match Char.ToLowerInvariant(specifier) with | 'x' -> sign * (int32OfUInt32 (Convert.ToUInt32(UInt64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture)))) - | 'b' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseBinaryUInt64 s p l))) - | 'o' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseOctalUInt64 s p l))) + | 'b' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseBinaryUInt64 (s.Substring(p))))) + | 'o' -> sign * (int32OfUInt32 (Convert.ToUInt32(parseOctalUInt64 (s.Substring(p))))) | _ -> Int32.Parse(s, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture) let ParseInt64 (s:string) = @@ -2451,8 +2449,8 @@ namespace Microsoft.FSharp.Core if p >= l then formatError() else match Char.ToLowerInvariant(specifier) with | 'x' -> sign *. Int64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture) - | 'b' -> sign *. (int64OfUInt64 (parseBinaryUInt64 s p l)) - | 'o' -> sign *. (int64OfUInt64 (parseOctalUInt64 s p l)) + | 'b' -> sign *. (int64OfUInt64 (parseBinaryUInt64 (s.Substring(p)))) + | 'o' -> sign *. (int64OfUInt64 (parseOctalUInt64 (s.Substring(p)))) | _ -> Int64.Parse(s, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture) let ParseUInt64 (s:string) : uint64 = @@ -2465,8 +2463,8 @@ namespace Microsoft.FSharp.Core if p >= l then formatError() else match specifier with | 'x' -> UInt64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture) - | 'b' -> parseBinaryUInt64 s p l - | 'o' -> parseOctalUInt64 s p l + | 'b' -> parseBinaryUInt64 (s.Substring(p)) + | 'o' -> parseOctalUInt64 (s.Substring(p)) | _ -> UInt64.Parse(s.Substring(p), NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture) diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index 0af96d71c9a6..dc8b2660163d 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -66,13 +66,11 @@ let get0OXB (s:string) (p:byref) l = let formatError() = raise (new System.FormatException(SR.GetString("bad format string"))) -let parseBinaryUInt64 (s:string) p l = - let rec parse n acc = if n < l then parse (n+1) (acc * 2UL + (match s.[n] with '0' -> 0UL | '1' -> 1UL | _ -> formatError())) else acc - parse p 0UL +let parseBinaryUInt64 (s:string) = + Convert.ToUInt64(s, 2) -let parseOctalUInt64 (s:string) p l = - let rec parse n acc = if n < l then parse (n+1) (acc * 8UL + (let c = s.[n] in if c >= '0' && c <= '7' then Convert.ToUInt64 c - Convert.ToUInt64 '0' else formatError())) else acc - parse p 0UL +let parseOctalUInt64 (s:string) = + Convert.ToUInt64(s, 8) let removeUnderscores (s:string) = match s with @@ -91,8 +89,8 @@ let parseInt32 (s:string) = match Char.ToLower(specifier,CultureInfo.InvariantCulture) with #endif | 'x' -> sign * (int32 (Convert.ToUInt32(UInt64.Parse(s.Substring(p), NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture)))) - | 'b' -> sign * (int32 (Convert.ToUInt32(parseBinaryUInt64 s p l))) - | 'o' -> sign * (int32 (Convert.ToUInt32(parseOctalUInt64 s p l))) + | 'b' -> sign * (int32 (Convert.ToUInt32(parseBinaryUInt64 (s.Substring(p))))) + | 'o' -> sign * (int32 (Convert.ToUInt32(parseOctalUInt64 (s.Substring(p))))) | _ -> Int32.Parse(s, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture) let lexemeTrimRightToInt32 args lexbuf n = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs index 8b88798ec448..9d92d474cffd 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs @@ -423,10 +423,47 @@ type LanguagePrimitivesModule() = let resultValue = LanguagePrimitives.ParseInt64 "0" Assert.AreEqual(0L, resultValue) + + CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseInt64 "9223372036854775808" |> ignore) + CheckThrowsFormatException(fun () -> LanguagePrimitives.ParseInt64 "" |> ignore) CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseInt64 null |> ignore) - + + [] + member this.ParseBinaryInt64() = + let resultValue = LanguagePrimitives.ParseInt64 "0b1100100" + Assert.AreEqual(typeof, resultValue.GetType()) + Assert.AreEqual(100L, resultValue) + + let resultValue = LanguagePrimitives.ParseInt64 "-0b101100011010001010111100001011101100010100000000000000000" + Assert.AreEqual(-100000000000000000L, resultValue) + + let resultValue = LanguagePrimitives.ParseInt64 "0b1111111010011100101110101000011110100010011101100000000000000000" + Assert.AreEqual(-100000000000000000L, resultValue) + + let resultValue = LanguagePrimitives.ParseInt64 "0b0" + Assert.AreEqual(0L, resultValue) + + CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseInt64 "0b10000000000000000000000000000000000000000000000000000000000000000" |> ignore) + + [] + member this.ParseOctalInt64() = + let resultValue = LanguagePrimitives.ParseInt64 "0o144" + Assert.AreEqual(typeof, resultValue.GetType()) + Assert.AreEqual(100L, resultValue) + + let resultValue = LanguagePrimitives.ParseInt64 "-0o5432127413542400000" + Assert.AreEqual(-100000000000000000L, resultValue) + + let resultValue = LanguagePrimitives.ParseInt64 "0o1772345650364235400000" + Assert.AreEqual(-100000000000000000L, resultValue) + + let resultValue = LanguagePrimitives.ParseInt64 "0o0" + Assert.AreEqual(0L, resultValue) + + CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseInt64 "0o2000000000000000000000" |> ignore) + [] member this.ParseUInt32() = let resultValue = LanguagePrimitives.ParseUInt32 "100" @@ -444,9 +481,28 @@ type LanguagePrimitivesModule() = Assert.AreEqual(100UL, resultValue) CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "-1" |> ignore) + CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "18446744073709551616" |> ignore) CheckThrowsArgumentNullException(fun () -> LanguagePrimitives.ParseUInt64 null |> ignore) + [] + member this.ParseBinaryUInt64() = + let resultValue = LanguagePrimitives.ParseUInt64 "0b1100100" + Assert.AreEqual(typeof, resultValue.GetType()) + Assert.AreEqual(100UL, resultValue) + + CheckThrowsFormatException(fun () -> LanguagePrimitives.ParseUInt64 "-0b1" |> ignore) + CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "0b10000000000000000000000000000000000000000000000000000000000000000" |> ignore) + + [] + member this.ParseOctalUInt64() = + let resultValue = LanguagePrimitives.ParseUInt64 "0o144" + Assert.AreEqual(typeof, resultValue.GetType()) + Assert.AreEqual(100UL, resultValue) + + CheckThrowsFormatException(fun () -> LanguagePrimitives.ParseUInt64 "-0o1" |> ignore) + CheckThrowsOverflowException(fun () -> LanguagePrimitives.ParseUInt64 "0o2000000000000000000000" |> ignore) + [] member this.ParseStringViaConversionOps() = let s : string = null diff --git a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/E_MaxLiterals04.fs b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/E_MaxLiterals04.fs new file mode 100644 index 000000000000..f451f17e3269 --- /dev/null +++ b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/E_MaxLiterals04.fs @@ -0,0 +1,11 @@ +// #Regression #Conformance #LexicalAnalysis #Constants + + +// Verify compile error for signed literals which are MaxSize + 1, MaxSize - 1 +// All of these should cause compiler errors + +//This number is outside the allowable range for 64-bit signed integers +//This number is outside the allowable range for 64-bit signed integers + +let int64Bin65bits = 0b1_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000L +let int64Octal65bits = 0o2_000_000_000_000_000_000_000L diff --git a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/env.lst b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/env.lst index 47fdc9891d62..17880073bf38 100644 --- a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/env.lst +++ b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/NumericLiterals/env.lst @@ -23,6 +23,7 @@ SOURCE=E_MaxLiterals01.fs # E_MaxLiterals01.fs SOURCE=E_MaxLiterals02.fs # E_MaxLiterals02.fs SOURCE=E_MaxLiterals03.fs # E_MaxLiterals03.fs + SOURCE=E_MaxLiterals04.fs # E_MaxLiterals04.fs SOURCE=BigNums01.fs # BigNums01.fs