[Support] Make JSON handle doubles and int64s losslessly

Summary:
This patch adds a new "integer" ValueType, and renames Number -> Double.
This allows us to preserve the full precision of int64_t when parsing integers
from the wire, or constructing from an integer.
The API is unchanged, other than giving asInteger() a clearer contract.

In addition, always output doubles with enough precision that parsing will
reconstruct the same double.

Reviewers: simon_tatham

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D46209

llvm-svn: 336541
diff --git a/llvm/unittests/Support/JSONTest.cpp b/llvm/unittests/Support/JSONTest.cpp
index bf7f4ae..08307c1 100644
--- a/llvm/unittests/Support/JSONTest.cpp
+++ b/llvm/unittests/Support/JSONTest.cpp
@@ -227,6 +227,66 @@
   }
 }
 
+// Verify special integer handling - we try to preserve exact int64 values.
+TEST(JSONTest, Integers) {
+  struct {
+    const char *Desc;
+    Value Val;
+    const char *Str;
+    llvm::Optional<int64_t> AsInt;
+    llvm::Optional<double> AsNumber;
+  } TestCases[] = {
+      {
+          "Non-integer. Stored as double, not convertible.",
+          double{1.5},
+          "1.5",
+          llvm::None,
+          1.5,
+      },
+
+      {
+          "Integer, not exact double. Stored as int64, convertible.",
+          int64_t{0x4000000000000001},
+          "4611686018427387905",
+          int64_t{0x4000000000000001},
+          double{0x4000000000000000},
+      },
+
+      {
+          "Negative integer, not exact double. Stored as int64, convertible.",
+          int64_t{-0x4000000000000001},
+          "-4611686018427387905",
+          int64_t{-0x4000000000000001},
+          double{-0x4000000000000000},
+      },
+
+      {
+          "Dynamically exact integer. Stored as double, convertible.",
+          double{0x6000000000000000},
+          "6.9175290276410819e+18",
+          int64_t{0x6000000000000000},
+          double{0x6000000000000000},
+      },
+
+      {
+          "Dynamically integer, >64 bits. Stored as double, not convertible.",
+          1.5 * double{0x8000000000000000},
+          "1.3835058055282164e+19",
+          llvm::None,
+          1.5 * double{0x8000000000000000},
+      },
+  };
+  for (const auto &T : TestCases) {
+    EXPECT_EQ(T.Str, s(T.Val)) << T.Desc;
+    llvm::Expected<Value> Doc = parse(T.Str);
+    EXPECT_TRUE(!!Doc) << T.Desc;
+    EXPECT_EQ(Doc->getAsInteger(), T.AsInt) << T.Desc;
+    EXPECT_EQ(Doc->getAsNumber(), T.AsNumber) << T.Desc;
+    EXPECT_EQ(T.Val, *Doc) << T.Desc;
+    EXPECT_EQ(T.Str, s(*Doc)) << T.Desc;
+  }
+}
+
 // Sample struct with typical JSON-mapping rules.
 struct CustomStruct {
   CustomStruct() : B(false) {}