Prepare DesugarCollections integration

- DesugarCollections now require some conversions methods to
  use the receiver of the converted api as the extra
  parameter.
- This patch will roll in Google3, so the desugared library
  changes necessary can be done, then the DesugarCollections
  fix will roll in r8.

Change-Id: I8a309c3cccc6c55271bcac9d0c4d5fba9aa602d9
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java
index 9bd1ba2..1233526 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.cf.code.CfLoad;
 import com.android.tools.r8.cf.code.CfReturn;
 import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexField;
@@ -94,7 +95,7 @@
     generatePushReceiver(instructions, isStatic);
     generateParameterConvertAndLoads(instructions, isStatic);
     generateForwardingCall(instructions);
-    generateReturnConversion(instructions);
+    generateReturnConversion(instructions, isStatic);
     generateReturn(instructions);
     return standardCfCodeFromInstructions(instructions);
   }
@@ -108,12 +109,29 @@
     }
   }
 
-  private void generateReturnConversion(List<CfInstruction> instructions) {
+  private void generateReturnConversion(List<CfInstruction> instructions, boolean isStatic) {
     if (returnConversion != null) {
-      instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, returnConversion, false));
+      generateConversion(instructions, returnConversion, isStatic);
     }
   }
 
+  private void generateConversion(
+      List<CfInstruction> instructions, DexMethod conversion, boolean isStatic) {
+    if (conversion.getArity() == 2) {
+      // If there is a second parameter, D8/R8 passes the  receiver as the second parameter.
+      if (isStatic) {
+        throw new CompilationError("Unsupported conversion with two parameters on static method");
+      }
+      generatePushReceiver(instructions, isStatic);
+    } else if (conversion.getArity() != 1) {
+      throw new CompilationError(
+          "Unsupported conversion with invalid number of parameters ("
+              + conversion.getArity()
+              + ")");
+    }
+    instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, conversion, false));
+  }
+
   private void generateForwardingCall(List<CfInstruction> instructions) {
     instructions.add(new CfInvoke(forwardCallOpcode, forwardMethod, itfCall));
   }
@@ -125,7 +143,7 @@
       ValueType valueType = valueTypeFromForwardMethod(forwardMethod.getParameter(i));
       instructions.add(new CfLoad(valueType, localIndex));
       if (parameterConversions[i] != null) {
-        instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, parameterConversions[i], false));
+        generateConversion(instructions, parameterConversions[i], isStatic);
       }
       localIndex += valueType.isWide() ? 2 : 1;
     }