Raise a compilation error when compiling with machine spec

Bug: b/247730422
Change-Id: Iaf7ac1b61616afc8a3ce8939b8150ffe2b8db583
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
index 83ee3ec..4bb5379 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.desugar.desugaredlibrary;
 
 import com.android.tools.r8.StringResource;
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
@@ -20,6 +21,7 @@
 
   public static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
   private static final int MIN_HUMAN_CONFIGURATION_FORMAT_VERSION = 100;
+  private static final int MIN_MACHINE_CONFIGURATION_FORMAT_VERSION = 200;
 
   public static DesugaredLibrarySpecification parseDesugaredLibrarySpecification(
       StringResource stringResource,
@@ -27,26 +29,8 @@
       Reporter reporter,
       boolean libraryCompilation,
       int minAPILevel) {
-    Origin origin = stringResource.getOrigin();
-    assert origin != null;
-    String jsonConfigString;
-    JsonObject jsonConfig;
-    try {
-      jsonConfigString = stringResource.getString();
-      JsonParser parser = new JsonParser();
-      jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
-    } catch (Exception e) {
-      throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
-    }
-
-    if (isHumanSpecification(jsonConfig, reporter, origin)) {
-      return new HumanDesugaredLibrarySpecificationParser(
-              dexItemFactory, reporter, libraryCompilation, minAPILevel)
-          .parse(origin, jsonConfigString, jsonConfig);
-    }
-    return new LegacyDesugaredLibrarySpecificationParser(
-            dexItemFactory, reporter, libraryCompilation, minAPILevel)
-        .parse(origin, jsonConfigString, jsonConfig);
+    return parseDesugaredLibrarySpecificationforTesting(
+        stringResource, dexItemFactory, reporter, libraryCompilation, minAPILevel, flags -> {});
   }
 
   public static DesugaredLibrarySpecification parseDesugaredLibrarySpecificationforTesting(
@@ -67,18 +51,53 @@
     } catch (Exception e) {
       throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
     }
+    // Machine Specification is the shippable format released in Maven. D8/R8 has to be *very*
+    // backward compatible to any machine specification, and raise proper error messages for
+    // compatibility issues. The format is also exhaustive (Very limited pattern matching, if any).
+    // It can hardly be written by hand and is always generated.
+    if (isMachineSpecification(jsonConfig, reporter, origin)) {
+      throw new CompilationError(
+          "Unsupported desugared library configuration version, please upgrade the D8/R8 compiler."
+              + " See https://developer.android.com/studio/build/library-desugaring-versions.");
+    }
+    // Human Specification is the easy to write format for developers and allows one to widely use
+    // pattern matching. This format is mainly used for development and to generate the machine
+    // specification. D8/R8 is *not* backward compatible with any previous version of human
+    // specification, which is therefore not suited to be shipped for external users. It can be
+    // shipped to internal users where we can easily update the D8/R8 compiler and the
+    // desugared library specification at the same time.
     if (isHumanSpecification(jsonConfig, reporter, origin)) {
       return new HumanDesugaredLibrarySpecificationParser(
               dexItemFactory, reporter, libraryCompilation, minAPILevel)
           .parse(origin, jsonConfigString, jsonConfig, topLevelFlagsAmender);
     }
+    // Legacy specification is the legacy format, as was shipped desugared library JDK8 or JDK11
+    // legacy. Hopefully the day will come where this format is no longer supported, and the other
+    // formats shall always be preferred.
     return new LegacyDesugaredLibrarySpecificationParser(
             dexItemFactory, reporter, libraryCompilation, minAPILevel)
         .parse(origin, jsonConfigString, jsonConfig, topLevelFlagsAmender);
   }
 
+  public static boolean isMachineSpecification(
+      JsonObject jsonConfig, Reporter reporter, Origin origin) {
+    ensureConfigurationFormatVersion(jsonConfig, reporter, origin);
+
+    int formatVersion = jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt();
+    return formatVersion >= MIN_MACHINE_CONFIGURATION_FORMAT_VERSION;
+  }
+
   public static boolean isHumanSpecification(
       JsonObject jsonConfig, Reporter reporter, Origin origin) {
+    ensureConfigurationFormatVersion(jsonConfig, reporter, origin);
+
+    int formatVersion = jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt();
+    return formatVersion >= MIN_HUMAN_CONFIGURATION_FORMAT_VERSION
+        && formatVersion < MIN_MACHINE_CONFIGURATION_FORMAT_VERSION;
+  }
+
+  private static void ensureConfigurationFormatVersion(
+      JsonObject jsonConfig, Reporter reporter, Origin origin) {
     if (!jsonConfig.has(CONFIGURATION_FORMAT_VERSION_KEY)) {
       throw reporter.fatalError(
           new StringDiagnostic(
@@ -87,8 +106,5 @@
                   + "'",
               origin));
     }
-
-    return jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt()
-        >= MIN_HUMAN_CONFIGURATION_FORMAT_VERSION;
   }
 }