Refine inlining constraints with target holder.

When a method has instructions with different targets, method's inlining
constraint is not simply a min of each instruction's Inliner.Constraint.
One regression example is http://b/111080693#comment6 (or go/r8g/23940).

This CL introduces ConstraintWithTarget, a wrapper of Constraint along
with its target holder, and tweak all uses of Constraint with it.
Calculation of min (or meet) of two ConstraintWithTarget take into
account target holders too so that constraints from unrelated items are
not incorrectly combined.

Bug: 111080693
Change-Id: Ic545b99a28ac1f97c3ff603ddb7824ad68111a0d
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 9a44dde..a6032e4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -32,7 +32,7 @@
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.Inliner.Reason;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
@@ -57,6 +57,7 @@
    * <p>
    * We also use this enum to encode under what constraints a method may be inlined.
    */
+  // TODO(b/111080693): Need to extend this to a state with the context.
   public enum CompilationState {
     /**
      * Has not been processed, yet.
@@ -72,7 +73,7 @@
      */
     PROCESSED_INLINING_CANDIDATE_ANY,
     /**
-     * Code also contains instructions that access protected entities that reside in a differnt
+     * Code also contains instructions that access protected entities that reside in a different
      * package and hence require subclass relationship to be visible.
      */
     PROCESSED_INLINING_CANDIDATE_SUBCLASS,
@@ -96,6 +97,8 @@
   public DexAnnotationSet annotations;
   public ParameterAnnotationsList parameterAnnotationsList;
   private Code code;
+  // TODO(b/111080693): towards finer-grained inlining constraints,
+  //   we need to maintain a set of states with (potentially different) contexts.
   private CompilationState compilationState = CompilationState.NOT_PROCESSED;
   private OptimizationInfo optimizationInfo = DefaultOptimizationInfo.DEFAULT;
   private int classFileVersion = -1;
@@ -208,6 +211,7 @@
       assert isInliningCandidate(containerType, Reason.SIMPLE, appInfo);
       return true;
     }
+    // TODO(b/111080693): inlining candidate should satisfy all states if multiple states are there.
     switch (compilationState) {
       case PROCESSED_INLINING_CANDIDATE_ANY:
         return true;
@@ -222,9 +226,9 @@
     }
   }
 
-  public boolean markProcessed(Constraint state) {
+  public boolean markProcessed(ConstraintWithTarget state) {
     CompilationState prevCompilationState = compilationState;
-    switch (state) {
+    switch (state.constraint) {
       case ALWAYS:
         compilationState = PROCESSED_INLINING_CANDIDATE_ANY;
         break;
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 2c37c6a..a48841f 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.JarSourceCode;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.jar.InliningConstraintVisitor;
 import com.android.tools.r8.jar.JarRegisterEffectsVisitor;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -173,7 +173,7 @@
             DescriptorUtils.getDescriptorFromClassBinaryName(tryCatchBlockNode.type))));
   }
 
-  public Constraint computeInliningConstraint(
+  public ConstraintWithTarget computeInliningConstraint(
       DexEncodedMethod encodedMethod,
       AppInfoWithLiveness appInfo,
       GraphLense graphLense,
diff --git a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java
index 6948a08..20d7bf4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java
+++ b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 
@@ -58,7 +58,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forAlwaysMaterializingUser();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java
index cff655a..c8240a0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Argument.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 
@@ -76,7 +76,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forArgument();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index 01101f3..758252b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -21,7 +21,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import java.util.Arrays;
@@ -133,7 +133,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forArrayGet();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index cc358f0..445c9ed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import java.util.function.Function;
@@ -90,7 +90,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forArrayLength();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index 023afce..0282ffa 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -17,7 +17,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.utils.InternalOptions;
@@ -154,7 +154,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forArrayPut();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Binop.java b/src/main/java/com/android/tools/r8/ir/code/Binop.java
index e5190bb..30fdc59 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Binop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Binop.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import java.util.function.Function;
@@ -124,7 +124,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forBinop();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
index dba575f..cee01eb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
@@ -15,7 +15,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 
@@ -113,7 +113,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forCheckCast(type, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index 3041aaf..c5a0a11 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.function.Function;
@@ -99,7 +99,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forConstClass(clazz, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java b/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java
index f6e212d..a6ac01d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstInstruction.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 
 public abstract class ConstInstruction extends Instruction {
@@ -29,7 +29,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forConstInstruction();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
index 637faf7..9c6b342 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 
@@ -60,7 +60,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forDebugLocalRead();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java
index 53791e5..52c8dc6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
@@ -100,7 +100,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forDebugLocalsChange();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
index aed2128..5a611aa 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 
@@ -57,7 +57,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forDebugPosition();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index 1083669..50fc2ed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -22,7 +22,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 import org.objectweb.asm.Opcodes;
@@ -114,7 +114,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInstanceGet(field, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
index 53fd31c..7a973f8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 
@@ -81,7 +81,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInstanceOf(type, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 3585348..e8d917d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -19,7 +19,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.Arrays;
 import org.objectweb.asm.Opcodes;
@@ -113,7 +113,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInstancePut(field, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index eb85222..d9bf8d0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -16,7 +16,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.utils.CfgPrinter;
@@ -1059,7 +1059,7 @@
    *
    * <p>The type is used to judge visibility constraints and also for dispatch decisions.
    */
-  public abstract Constraint inliningConstraint(
+  public abstract ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext);
 
   public abstract void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper);
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
index a6e6fd1..c12333a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.List;
 
@@ -101,7 +101,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeCustom();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index 88716dc..46d2e5a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import java.util.Collection;
@@ -113,7 +113,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeDirect(getInvokedMethod(), invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
index 06d368d..5f49322 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeEnvironment;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import java.util.Collection;
@@ -95,7 +95,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeInterface(getInvokedMethod(), invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
index e34d25f..821d707 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.List;
 import java.util.function.Function;
@@ -69,7 +69,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeMultiNewArray(type, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index a2a9c36..17f36df 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.List;
 import java.util.function.Function;
@@ -99,7 +99,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeNewArray(type, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
index 8f90630..b45e984 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.optimize.InliningOracle;
@@ -126,7 +126,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokePolymorphic(getInvokedMethod(), invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index d2183c0..93660c7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.optimize.InliningOracle;
@@ -103,7 +103,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeStatic(getInvokedMethod(), invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
index 920d94b..141d4d9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeEnvironment;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import java.util.Collection;
@@ -112,7 +112,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeSuper(getInvokedMethod(), invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index f55a407..51bed08 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeEnvironment;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import java.util.Collection;
@@ -95,7 +95,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forInvokeVirtual(getInvokedMethod(), invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
index 6096292..ded6002 100644
--- a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.List;
@@ -47,7 +47,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forJumpInstruction();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Load.java b/src/main/java/com/android/tools/r8/ir/code/Load.java
index 32654b8..5981249 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Load.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Load.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 
 public class Load extends Instruction {
@@ -51,7 +51,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forLoad();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Monitor.java b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
index 3b1b2d1..70af068 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Monitor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 
 public class Monitor extends Instruction {
@@ -97,7 +97,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forMonitor();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Move.java b/src/main/java/com/android/tools/r8/ir/code/Move.java
index e474bb8..6223501 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Move.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Move.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 
@@ -100,7 +100,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forMove();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index eabf7b2..e7d6e63 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.HashSet;
@@ -75,7 +75,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forMoveException();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index edca979..69867e6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 
@@ -84,7 +84,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forNewArrayEmpty(type, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index ac46cc7..8dac404 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.Arrays;
@@ -112,7 +112,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forNewArrayFilledData();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 75931ad..92e7f3e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 
@@ -81,7 +81,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forNewInstance(clazz, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NonNull.java b/src/main/java/com/android/tools/r8/ir/code/NonNull.java
index 462af06..d909144 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NonNull.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NonNull.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 
@@ -85,7 +85,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forNonNull();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Pop.java b/src/main/java/com/android/tools/r8/ir/code/Pop.java
index 0fb1949..8ea55dd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Pop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Pop.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 
@@ -50,7 +50,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forPop();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index 37cfaf0..bb750c2 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -15,7 +15,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 
 public class Return extends JumpInstruction {
@@ -116,7 +116,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forReturn();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index 486f9e2..108beee 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -21,7 +21,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 import org.objectweb.asm.Opcodes;
@@ -109,7 +109,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forStaticGet(field, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index f910ff6..8824d54 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -18,7 +18,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import org.objectweb.asm.Opcodes;
 
@@ -107,7 +107,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forStaticPut(field, invocationContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Store.java b/src/main/java/com/android/tools/r8/ir/code/Store.java
index b81af69..cec5501 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Store.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Store.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.utils.InternalOptions;
 
@@ -53,7 +53,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forStore();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Throw.java b/src/main/java/com/android/tools/r8/ir/code/Throw.java
index 4295dbe..7bda1c8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Throw.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Throw.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 
 public class Throw extends JumpInstruction {
@@ -65,7 +65,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forThrow();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Unop.java b/src/main/java/com/android/tools/r8/ir/code/Unop.java
index 2f6ed7f..b29afd0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Unop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Unop.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import java.util.function.Function;
 
@@ -48,7 +48,7 @@
   }
 
   @Override
-  public Constraint inliningConstraint(
+  public ConstraintWithTarget inliningConstraint(
       InliningConstraints inliningConstraints, DexType invocationContext) {
     return inliningConstraints.forUnop();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 33531da..eef5967 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -41,7 +41,7 @@
 import com.android.tools.r8.ir.optimize.DeadCodeRemover;
 import com.android.tools.r8.ir.optimize.Devirtualizer;
 import com.android.tools.r8.ir.optimize.Inliner;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.MemberValuePropagation;
 import com.android.tools.r8.ir.optimize.NonNullTracker;
 import com.android.tools.r8.ir.optimize.Outliner;
@@ -605,7 +605,7 @@
       rewriteCode(method, feedback, isProcessedConcurrently, callSiteInformation, outlineHandler);
     } else {
       // Mark abstract methods as processed as well.
-      method.markProcessed(Constraint.NEVER);
+      method.markProcessed(ConstraintWithTarget.NEVER);
     }
   }
 
@@ -632,12 +632,12 @@
           method.toSourceString(), logCode(options, method));
     }
     if (options.skipIR) {
-      feedback.markProcessed(method, Constraint.NEVER);
+      feedback.markProcessed(method, ConstraintWithTarget.NEVER);
       return;
     }
     IRCode code = method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
     if (code == null) {
-      feedback.markProcessed(method, Constraint.NEVER);
+      feedback.markProcessed(method, ConstraintWithTarget.NEVER);
       return;
     }
     if (Log.ENABLED) {
@@ -869,9 +869,9 @@
 
   private void markProcessed(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
     // After all the optimizations have take place, we compute whether method should be inlinedex.
-    Constraint state;
+    ConstraintWithTarget state;
     if (!options.enableInlining || inliner == null) {
-      state = Constraint.NEVER;
+      state = ConstraintWithTarget.NEVER;
     } else {
       state = inliner.computeInliningConstraint(code, method);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
index 49bfac8..0833579 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod.ClassInlinerEligibility;
 import com.android.tools.r8.graph.ParameterUsagesInfo;
 import com.android.tools.r8.graph.DexEncodedMethod.TrivialInitializer;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import java.util.BitSet;
 
 public interface OptimizationFeedback {
@@ -16,7 +16,7 @@
   void methodReturnsConstant(DexEncodedMethod method, long value);
   void methodNeverReturnsNull(DexEncodedMethod method);
   void methodNeverReturnsNormally(DexEncodedMethod method);
-  void markProcessed(DexEncodedMethod method, Constraint state);
+  void markProcessed(DexEncodedMethod method, ConstraintWithTarget state);
   void markCheckNullReceiverBeforeAnySideEffect(DexEncodedMethod method, boolean mark);
   void markTriggerClassInitBeforeAnySideEffect(DexEncodedMethod method, boolean mark);
   void setClassInlinerEligibility(DexEncodedMethod method, ClassInlinerEligibility eligibility);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java
index 1d7a2d6..16267f6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod.ClassInlinerEligibility;
 import com.android.tools.r8.graph.ParameterUsagesInfo;
 import com.android.tools.r8.graph.DexEncodedMethod.TrivialInitializer;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import java.util.BitSet;
 
 public class OptimizationFeedbackDirect implements OptimizationFeedback {
@@ -34,7 +34,7 @@
   }
 
   @Override
-  public void markProcessed(DexEncodedMethod method, Constraint state) {
+  public void markProcessed(DexEncodedMethod method, ConstraintWithTarget state) {
     method.markProcessed(state);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
index 2fb2969..a27f200 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod.ClassInlinerEligibility;
 import com.android.tools.r8.graph.ParameterUsagesInfo;
 import com.android.tools.r8.graph.DexEncodedMethod.TrivialInitializer;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import java.util.BitSet;
 
 public class OptimizationFeedbackIgnore implements OptimizationFeedback {
@@ -26,7 +26,7 @@
   public void methodNeverReturnsNormally(DexEncodedMethod method) {}
 
   @Override
-  public void markProcessed(DexEncodedMethod method, Constraint state) {}
+  public void markProcessed(DexEncodedMethod method, ConstraintWithTarget state) {}
 
   @Override
   public void markCheckNullReceiverBeforeAnySideEffect(DexEncodedMethod method, boolean mark) {}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
index b31f28a..2583f8f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod.ClassInlinerEligibility;
 import com.android.tools.r8.graph.DexEncodedMethod.TrivialInitializer;
 import com.android.tools.r8.graph.ParameterUsagesInfo;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import java.util.BitSet;
 
 public class OptimizationFeedbackSimple implements OptimizationFeedback {
@@ -34,9 +34,9 @@
   }
 
   @Override
-  public void markProcessed(DexEncodedMethod method, Constraint state) {
+  public void markProcessed(DexEncodedMethod method, ConstraintWithTarget state) {
     // Just as processed, don't provide any inlining constraints.
-    method.markProcessed(Constraint.NEVER);
+    method.markProcessed(ConstraintWithTarget.NEVER);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index e6de678..eb3511b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -18,7 +18,7 @@
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.NonNull;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -86,8 +86,9 @@
           continue;
         }
         // Due to the potential downcast below, make sure the new target holder is visible.
-        Constraint visibility = Constraint.classIsVisible(invocationContext, holderType, appInfo);
-        if (visibility == Constraint.NEVER) {
+        ConstraintWithTarget visibility =
+            ConstraintWithTarget.classIsVisible(invocationContext, holderType, appInfo);
+        if (visibility == ConstraintWithTarget.NEVER) {
           continue;
         }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index db674bd..283716b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -74,27 +74,30 @@
     return blackList.contains(method.method) || appInfo.neverInline.contains(method);
   }
 
-  private Constraint instructionAllowedForInlining(
+  private ConstraintWithTarget instructionAllowedForInlining(
       Instruction instruction, InliningConstraints inliningConstraints, DexType invocationContext) {
-    Constraint result = instruction.inliningConstraint(inliningConstraints, invocationContext);
-    if (result == Constraint.NEVER && instruction.isDebugInstruction()) {
-      return Constraint.ALWAYS;
+    ConstraintWithTarget result =
+        instruction.inliningConstraint(inliningConstraints, invocationContext);
+    if (result == ConstraintWithTarget.NEVER && instruction.isDebugInstruction()) {
+      return ConstraintWithTarget.ALWAYS;
     }
     return result;
   }
 
-  public Constraint computeInliningConstraint(IRCode code, DexEncodedMethod method) {
-    Constraint result = Constraint.ALWAYS;
+  public ConstraintWithTarget computeInliningConstraint(IRCode code, DexEncodedMethod method) {
+    ConstraintWithTarget result = ConstraintWithTarget.ALWAYS;
     InliningConstraints inliningConstraints = new InliningConstraints(appInfo);
     InstructionIterator it = code.instructionIterator();
     while (it.hasNext()) {
       Instruction instruction = it.next();
-      Constraint state =
+      ConstraintWithTarget state =
           instructionAllowedForInlining(instruction, inliningConstraints, method.method.holder);
-      result = Constraint.min(result, state);
-      if (result == Constraint.NEVER) {
+      if (state == ConstraintWithTarget.NEVER) {
+        result = state;
         break;
       }
+      // TODO(b/111080693): we may need to collect all meaningful constraints.
+      result = ConstraintWithTarget.min(result, state, appInfo);
     }
     return result;
   }
@@ -178,8 +181,8 @@
     // The ordinal values are important so please do not reorder.
     NEVER,     // Never inline this.
     SAMECLASS, // Only inline this into methods with same holder.
-    PACKAGE,   // Only inline this into methods with holders from same package.
-    SUBCLASS,  // Only inline this into methods with holders from a subclass.
+    PACKAGE,   // Only inline this into methods with holders from the same package.
+    SUBCLASS,  // Only inline this into methods with holders from a subclass in a different package.
     ALWAYS;    // No restrictions for inlining this.
 
     static {
@@ -189,7 +192,67 @@
       assert SUBCLASS.ordinal() < ALWAYS.ordinal();
     }
 
-    public static Constraint deriveConstraint(
+    static Constraint min(Constraint one, Constraint other) {
+      return one.ordinal() < other.ordinal() ? one : other;
+    }
+  }
+
+  /**
+   * Encodes the constraints for inlining, along with the target holder.
+   * <p>
+   * Constraint itself cannot determine whether or not the method can be inlined if instructions in
+   * the method have different constraints with different targets. For example,
+   *   SUBCLASS of x.A v.s. PACKAGE of y.B
+   * Without any target holder information, min of those two Constraints is PACKAGE, meaning that
+   * the current method can be inlined to any method whose holder is in package y. This could cause
+   * an illegal access error due to protect members in x.A. Because of different target holders,
+   * those constraints should not be combined.
+   * <p>
+   * Instead, a right constraint for inlining constraint for the example above is: a method whose
+   * holder is a subclass of x.A _and_ in the same package of y.B can inline this method.
+   */
+  public static class ConstraintWithTarget {
+    public final Constraint constraint;
+    // Note that this is not context---where this constraint is encoded.
+    // It literally refers to the holder type of the target, which could be:
+    // invoked method in invocations, field in field instructions, type of check-cast, etc.
+    final DexType targetHolder;
+
+    public static final ConstraintWithTarget NEVER = new ConstraintWithTarget(Constraint.NEVER);
+    public static final ConstraintWithTarget ALWAYS = new ConstraintWithTarget(Constraint.ALWAYS);
+
+    private ConstraintWithTarget(Constraint constraint) {
+      assert constraint == Constraint.NEVER || constraint == Constraint.ALWAYS;
+      this.constraint = constraint;
+      this.targetHolder = null;
+    }
+
+    ConstraintWithTarget(Constraint constraint, DexType targetHolder) {
+      assert constraint != Constraint.NEVER && constraint != Constraint.ALWAYS;
+      assert targetHolder != null;
+      this.constraint = constraint;
+      this.targetHolder = targetHolder;
+    }
+
+    @Override
+    public int hashCode() {
+      if (targetHolder == null) {
+        return constraint.ordinal();
+      }
+      return constraint.ordinal() * targetHolder.computeHashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+      if (!(other instanceof ConstraintWithTarget)) {
+        return false;
+      }
+      ConstraintWithTarget o = (ConstraintWithTarget) other;
+      return this.constraint.ordinal() == o.constraint.ordinal()
+          && this.targetHolder == o.targetHolder;
+    }
+
+    public static ConstraintWithTarget deriveConstraint(
         DexType contextHolder,
         DexType targetHolder,
         AccessFlags flags,
@@ -197,23 +260,25 @@
       if (flags.isPublic()) {
         return ALWAYS;
       } else if (flags.isPrivate()) {
-        return targetHolder == contextHolder ? SAMECLASS : NEVER;
+        return targetHolder == contextHolder
+            ? new ConstraintWithTarget(Constraint.SAMECLASS, targetHolder) : NEVER;
       } else if (flags.isProtected()) {
         if (targetHolder.isSamePackage(contextHolder)) {
           // Even though protected, this is visible via the same package from the context.
-          return PACKAGE;
+          return new ConstraintWithTarget(Constraint.PACKAGE, targetHolder);
         } else if (contextHolder.isSubtypeOf(targetHolder, appInfo)) {
-          return SUBCLASS;
+          return new ConstraintWithTarget(Constraint.SUBCLASS, targetHolder);
         }
         return NEVER;
       } else {
         /* package-private */
-        return targetHolder.isSamePackage(contextHolder) ? PACKAGE : NEVER;
+        return targetHolder.isSamePackage(contextHolder)
+            ? new ConstraintWithTarget(Constraint.PACKAGE, targetHolder) : NEVER;
       }
     }
 
-    public static Constraint classIsVisible(DexType context, DexType clazz,
-        AppInfoWithSubtyping appInfo) {
+    public static ConstraintWithTarget classIsVisible(
+        DexType context, DexType clazz, AppInfoWithSubtyping appInfo) {
       if (clazz.isArrayType()) {
         return classIsVisible(context, clazz.toArrayElementType(appInfo.dexItemFactory), appInfo);
       }
@@ -227,8 +292,76 @@
           : deriveConstraint(context, clazz, definition.accessFlags, appInfo);
     }
 
-    public static Constraint min(Constraint one, Constraint other) {
-      return one.ordinal() < other.ordinal() ? one : other;
+    public static ConstraintWithTarget min(
+        ConstraintWithTarget one, ConstraintWithTarget other, AppInfoWithSubtyping appInfo) {
+      if (one.equals(other)) {
+        return one;
+      }
+      if (one == NEVER || other == NEVER) {
+        return NEVER;
+      }
+      if (other.constraint.ordinal() < one.constraint.ordinal()) {
+        return min(other, one, appInfo);
+      }
+      // From now on, one.constraint.ordinal() <= other.constraint.ordinal()
+      if (other == ALWAYS) {
+        return one;
+      }
+      Constraint minConstraint = Constraint.min(one.constraint, other.constraint);
+      assert minConstraint != Constraint.NEVER;
+      assert minConstraint != Constraint.ALWAYS;
+      // SAMECLASS <= SAMECLASS, PACKAGE, SUBCLASS
+      if (minConstraint == Constraint.SAMECLASS) {
+        assert one.constraint == Constraint.SAMECLASS;
+        if (other.constraint == Constraint.SAMECLASS) {
+          assert one.targetHolder != other.targetHolder;
+          return NEVER;
+        }
+        if (other.constraint == Constraint.PACKAGE) {
+          if (one.targetHolder.isSamePackage(other.targetHolder)) {
+            return one;
+          }
+          return NEVER;
+        }
+        assert other.constraint == Constraint.SUBCLASS;
+        if (one.targetHolder.isSubtypeOf(other.targetHolder, appInfo)) {
+          return one;
+        }
+        return NEVER;
+      }
+      // PACKAGE <= PACKAGE, SUBCLASS
+      if (minConstraint == Constraint.PACKAGE) {
+        assert one.constraint == Constraint.PACKAGE;
+        if (other.constraint == Constraint.PACKAGE) {
+          assert one.targetHolder != other.targetHolder;
+          if (one.targetHolder.isSamePackage(other.targetHolder)) {
+            return one;
+          }
+          // PACKAGE of x and PACKAGE of y can be satisfied together.
+          return NEVER;
+        }
+        assert other.constraint == Constraint.SUBCLASS;
+        if (other.targetHolder.isSamePackage(one.targetHolder)) {
+          // Then, PACKAGE is more restrictive constraint.
+          return one;
+        }
+        // TODO(b/111080693): towards finer-grained constraints, we need both.
+        // Even though they're in different package, it is still inlinable to a class that is
+        // in the same package of one's context and a sub type of other's context.
+        return NEVER;
+      }
+      // SUBCLASS <= SUBCLASS
+      assert minConstraint == Constraint.SUBCLASS;
+      assert one.constraint == other.constraint;
+      assert one.targetHolder != other.targetHolder;
+      if (one.targetHolder.isSubtypeOf(other.targetHolder, appInfo)) {
+        return one;
+      }
+      if (other.targetHolder.isSubtypeOf(one.targetHolder, appInfo)) {
+        return other;
+      }
+      // SUBCLASS of x and SUBCLASS of y while x and y are not a subtype of each other.
+      return NEVER;
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index 073d6ae..fe10637 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import java.util.Collection;
 
@@ -45,71 +46,71 @@
     this.graphLense = graphLense;
   }
 
-  public Constraint forAlwaysMaterializingUser() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forAlwaysMaterializingUser() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forArgument() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forArgument() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forArrayGet() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forArrayGet() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forArrayLength() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forArrayLength() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forArrayPut() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forArrayPut() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forBinop() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forBinop() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forCheckCast(DexType type, DexType invocationContext) {
-    return Constraint.classIsVisible(invocationContext, type, appInfo);
+  public ConstraintWithTarget forCheckCast(DexType type, DexType invocationContext) {
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
   }
 
-  public Constraint forConstClass(DexType type, DexType invocationContext) {
-    return Constraint.classIsVisible(invocationContext, type, appInfo);
+  public ConstraintWithTarget forConstClass(DexType type, DexType invocationContext) {
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
   }
 
-  public Constraint forConstInstruction() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forConstInstruction() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forDebugLocalRead() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forDebugLocalRead() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forDebugLocalsChange() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forDebugLocalsChange() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forDebugPosition() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forDebugPosition() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forInstanceGet(DexField field, DexType invocationContext) {
+  public ConstraintWithTarget forInstanceGet(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
         lookup, appInfo.lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
   }
 
-  public Constraint forInstanceOf(DexType type, DexType invocationContext) {
-    return Constraint.classIsVisible(invocationContext, type, appInfo);
+  public ConstraintWithTarget forInstanceOf(DexType type, DexType invocationContext) {
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
   }
 
-  public Constraint forInstancePut(DexField field, DexType invocationContext) {
+  public ConstraintWithTarget forInstancePut(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
         lookup, appInfo.lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
   }
 
-  public Constraint forInvoke(DexMethod method, Type type, DexType invocationContext) {
+  public ConstraintWithTarget forInvoke(DexMethod method, Type type, DexType invocationContext) {
     switch (type) {
       case DIRECT:
         return forInvokeDirect(method, invocationContext);
@@ -130,162 +131,165 @@
     }
   }
 
-  public Constraint forInvokeCustom() {
-    return Constraint.NEVER;
+  public ConstraintWithTarget forInvokeCustom() {
+    return ConstraintWithTarget.NEVER;
   }
 
-  public Constraint forInvokeDirect(DexMethod method, DexType invocationContext) {
+  public ConstraintWithTarget forInvokeDirect(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
     return forSingleTargetInvoke(lookup, appInfo.lookupDirectTarget(lookup), invocationContext);
   }
 
-  public Constraint forInvokeInterface(DexMethod method, DexType invocationContext) {
+  public ConstraintWithTarget forInvokeInterface(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
     return forVirtualInvoke(lookup, appInfo.lookupInterfaceTargets(lookup), invocationContext);
   }
 
-  public Constraint forInvokeMultiNewArray(DexType type, DexType invocationContext) {
-    return Constraint.classIsVisible(invocationContext, type, appInfo);
+  public ConstraintWithTarget forInvokeMultiNewArray(DexType type, DexType invocationContext) {
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
   }
 
-  public Constraint forInvokeNewArray(DexType type, DexType invocationContext) {
-    return Constraint.classIsVisible(invocationContext, type, appInfo);
+  public ConstraintWithTarget forInvokeNewArray(DexType type, DexType invocationContext) {
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
   }
 
-  public Constraint forInvokePolymorphic(DexMethod method, DexType invocationContext) {
-    return Constraint.NEVER;
+  public ConstraintWithTarget forInvokePolymorphic(DexMethod method, DexType invocationContext) {
+    return ConstraintWithTarget.NEVER;
   }
 
-  public Constraint forInvokeStatic(DexMethod method, DexType invocationContext) {
+  public ConstraintWithTarget forInvokeStatic(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
     return forSingleTargetInvoke(lookup, appInfo.lookupStaticTarget(lookup), invocationContext);
   }
 
-  public Constraint forInvokeSuper(DexMethod method, DexType invocationContext) {
+  public ConstraintWithTarget forInvokeSuper(DexMethod method, DexType invocationContext) {
     // The semantics of invoke super depend on the context.
-    return Constraint.SAMECLASS;
+    return new ConstraintWithTarget(Constraint.SAMECLASS, invocationContext);
   }
 
-  public Constraint forInvokeVirtual(DexMethod method, DexType invocationContext) {
+  public ConstraintWithTarget forInvokeVirtual(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
     return forVirtualInvoke(lookup, appInfo.lookupVirtualTargets(lookup), invocationContext);
   }
 
-  public Constraint forJumpInstruction() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forJumpInstruction() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forLoad() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forLoad() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forMonitor() {
+  public ConstraintWithTarget forMonitor() {
     // Conservative choice.
-    return Constraint.NEVER;
+    return ConstraintWithTarget.NEVER;
   }
 
-  public Constraint forMove() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forMove() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forMoveException() {
+  public ConstraintWithTarget forMoveException() {
     // TODO(64432527): Revisit this constraint.
-    return Constraint.NEVER;
+    return ConstraintWithTarget.NEVER;
   }
 
-  public Constraint forNewArrayEmpty(DexType type, DexType invocationContext) {
-    return Constraint.classIsVisible(invocationContext, type, appInfo);
+  public ConstraintWithTarget forNewArrayEmpty(DexType type, DexType invocationContext) {
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
   }
 
-  public Constraint forNewArrayFilledData() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forNewArrayFilledData() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forNewInstance(DexType type, DexType invocationContext) {
-    return Constraint.classIsVisible(invocationContext, type, appInfo);
+  public ConstraintWithTarget forNewInstance(DexType type, DexType invocationContext) {
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
   }
 
-  public Constraint forNonNull() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forNonNull() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forPop() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forPop() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forReturn() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forReturn() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forStaticGet(DexField field, DexType invocationContext) {
+  public ConstraintWithTarget forStaticGet(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
         lookup, appInfo.lookupStaticTarget(lookup.clazz, lookup), invocationContext);
   }
 
-  public Constraint forStaticPut(DexField field, DexType invocationContext) {
+  public ConstraintWithTarget forStaticPut(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
         lookup, appInfo.lookupStaticTarget(lookup.clazz, lookup), invocationContext);
   }
 
-  public Constraint forStore() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forStore() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forThrow() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forThrow() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint forUnop() {
-    return Constraint.ALWAYS;
+  public ConstraintWithTarget forUnop() {
+    return ConstraintWithTarget.ALWAYS;
   }
 
-  private Constraint forFieldInstruction(
+  private ConstraintWithTarget forFieldInstruction(
       DexField field, DexEncodedField target, DexType invocationContext) {
     // Resolve the field if possible and decide whether the instruction can inlined.
     DexType fieldHolder = graphLense.lookupType(field.clazz);
     DexClass fieldClass = appInfo.definitionFor(fieldHolder);
     if (target != null && fieldClass != null) {
-      Constraint fieldConstraint =
-          Constraint.deriveConstraint(invocationContext, fieldHolder, target.accessFlags, appInfo);
-      Constraint classConstraint =
-          Constraint.deriveConstraint(
+      ConstraintWithTarget fieldConstraintWithTarget =
+          ConstraintWithTarget.deriveConstraint(
+              invocationContext, fieldHolder, target.accessFlags, appInfo);
+      ConstraintWithTarget classConstraintWithTarget =
+          ConstraintWithTarget.deriveConstraint(
               invocationContext, fieldHolder, fieldClass.accessFlags, appInfo);
-      return Constraint.min(fieldConstraint, classConstraint);
+      return ConstraintWithTarget.min(
+          fieldConstraintWithTarget, classConstraintWithTarget, appInfo);
     }
-    return Constraint.NEVER;
+    return ConstraintWithTarget.NEVER;
   }
 
-  private Constraint forSingleTargetInvoke(
+  private ConstraintWithTarget forSingleTargetInvoke(
       DexMethod method, DexEncodedMethod target, DexType invocationContext) {
     if (method.holder.isArrayType()) {
-      return Constraint.ALWAYS;
+      return ConstraintWithTarget.ALWAYS;
     }
     if (target != null) {
       DexType methodHolder = graphLense.lookupType(target.method.holder);
       DexClass methodClass = appInfo.definitionFor(methodHolder);
       if (methodClass != null) {
-        Constraint methodConstraint =
-            Constraint.deriveConstraint(
+        ConstraintWithTarget methodConstraintWithTarget =
+            ConstraintWithTarget.deriveConstraint(
                 invocationContext, methodHolder, target.accessFlags, appInfo);
         // We also have to take the constraint of the enclosing class into account.
-        Constraint classConstraint =
-            Constraint.deriveConstraint(
+        ConstraintWithTarget classConstraintWithTarget =
+            ConstraintWithTarget.deriveConstraint(
                 invocationContext, methodHolder, methodClass.accessFlags, appInfo);
-        return Constraint.min(methodConstraint, classConstraint);
+        return ConstraintWithTarget.min(
+            methodConstraintWithTarget, classConstraintWithTarget, appInfo);
       }
     }
-    return Constraint.NEVER;
+    return ConstraintWithTarget.NEVER;
   }
 
-  private Constraint forVirtualInvoke(
+  private ConstraintWithTarget forVirtualInvoke(
       DexMethod method, Collection<DexEncodedMethod> targets, DexType invocationContext) {
     if (method.holder.isArrayType()) {
-      return Constraint.ALWAYS;
+      return ConstraintWithTarget.ALWAYS;
     }
     if (targets == null) {
-      return Constraint.NEVER;
+      return ConstraintWithTarget.NEVER;
     }
 
     // Perform resolution and derive inlining constraints based on the accessibility of the
@@ -294,25 +298,26 @@
     DexEncodedMethod resolutionTarget = resolutionResult.asResultOfResolve();
     if (resolutionTarget == null) {
       // This will fail at runtime.
-      return Constraint.NEVER;
+      return ConstraintWithTarget.NEVER;
     }
 
     DexType methodHolder = graphLense.lookupType(resolutionTarget.method.holder);
     DexClass methodClass = appInfo.definitionFor(methodHolder);
     assert methodClass != null;
-    Constraint methodConstraint =
-        Constraint.deriveConstraint(
+    ConstraintWithTarget methodConstraintWithTarget =
+        ConstraintWithTarget.deriveConstraint(
             invocationContext, methodHolder, resolutionTarget.accessFlags, appInfo);
     // We also have to take the constraint of the enclosing class of the resolution result
     // into account. We do not allow inlining this method if it is calling something that
     // is inaccessible. Inlining in that case could move the code to another package making a
     // call succeed that should not succeed. Conversely, if the resolution result is accessible,
     // we have to make sure that inlining cannot make it inaccessible.
-    Constraint classConstraint =
-        Constraint.deriveConstraint(
+    ConstraintWithTarget classConstraintWithTarget =
+        ConstraintWithTarget.deriveConstraint(
             invocationContext, methodHolder, methodClass.accessFlags, appInfo);
-    Constraint result = Constraint.min(methodConstraint, classConstraint);
-    if (result == Constraint.NEVER) {
+    ConstraintWithTarget result =
+        ConstraintWithTarget.min(methodConstraintWithTarget, classConstraintWithTarget, appInfo);
+    if (result == ConstraintWithTarget.NEVER) {
       return result;
     }
 
@@ -321,10 +326,11 @@
     for (DexEncodedMethod target : targets) {
       methodHolder = graphLense.lookupType(target.method.holder);
       assert appInfo.definitionFor(methodHolder) != null;
-      methodConstraint =
-          Constraint.deriveConstraint(invocationContext, methodHolder, target.accessFlags, appInfo);
-      result = Constraint.min(result, methodConstraint);
-      if (result == Constraint.NEVER) {
+      methodConstraintWithTarget =
+          ConstraintWithTarget.deriveConstraint(
+              invocationContext, methodHolder, target.accessFlags, appInfo);
+      result = ConstraintWithTarget.min(result, methodConstraintWithTarget, appInfo);
+      if (result == ConstraintWithTarget.NEVER) {
         return result;
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index c3a3781..73812ec 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -44,7 +44,7 @@
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.SynthesizedOrigin;
@@ -476,8 +476,9 @@
 
       // See whether we could move this invoke somewhere else. We reuse the logic from inlining
       // here, as the constraints are the same.
-      Constraint constraint = invoke.inliningConstraint(inliningConstraints, method.method.holder);
-      if (constraint != Constraint.ALWAYS) {
+      ConstraintWithTarget constraint =
+          invoke.inliningConstraint(inliningConstraints, method.method.holder);
+      if (constraint != ConstraintWithTarget.ALWAYS) {
         return false;
       }
       // Find the number of in-going arguments, if adding this instruction.
diff --git a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
index 459d7de..dbc48a3 100644
--- a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
+++ b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
@@ -17,7 +17,7 @@
 import com.android.tools.r8.graph.JarApplicationReader;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.conversion.JarSourceCode;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import org.objectweb.asm.MethodVisitor;
@@ -40,7 +40,7 @@
   private final DexEncodedMethod method;
   private final DexType invocationContext;
 
-  private Constraint constraint;
+  private ConstraintWithTarget constraint;
 
   public InliningConstraintVisitor(
       JarApplicationReader application,
@@ -58,22 +58,22 @@
     this.invocationContext = invocationContext;
 
     // Model a synchronized method as having a monitor instruction.
-    this.constraint =
-        method.accessFlags.isSynchronized() ? inliningConstraints.forMonitor() : Constraint.ALWAYS;
+    this.constraint = method.accessFlags.isSynchronized()
+        ? inliningConstraints.forMonitor() : ConstraintWithTarget.ALWAYS;
   }
 
-  public Constraint getConstraint() {
+  public ConstraintWithTarget getConstraint() {
     return constraint;
   }
 
-  private void updateConstraint(Constraint other) {
-    constraint = Constraint.min(constraint, other);
+  private void updateConstraint(ConstraintWithTarget other) {
+    constraint = ConstraintWithTarget.min(constraint, other, appInfo);
   }
 
   // Used to signal that the result is ready, such that we do not need to visit all instructions of
   // the method, if we can see early on that it cannot be inlined anyway.
   public boolean isFinished() {
-    return constraint == Constraint.NEVER;
+    return constraint == ConstraintWithTarget.NEVER;
   }
 
   public void accept(TryCatchBlockNode tryCatchBlock) {
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index fe098cc..c1d7403 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLense;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
@@ -208,14 +208,14 @@
     if (holder == null) {
       return false;
     }
-    Constraint classVisibility =
-        Constraint.deriveConstraint(context, holderType, holder.accessFlags, appInfo);
-    if (classVisibility == Constraint.NEVER) {
+    ConstraintWithTarget classVisibility =
+        ConstraintWithTarget.deriveConstraint(context, holderType, holder.accessFlags, appInfo);
+    if (classVisibility == ConstraintWithTarget.NEVER) {
       return false;
     }
-    Constraint fieldVisibility =
-        Constraint.deriveConstraint(context, holderType, field.accessFlags, appInfo);
-    return fieldVisibility != Constraint.NEVER;
+    ConstraintWithTarget fieldVisibility =
+        ConstraintWithTarget.deriveConstraint(context, holderType, field.accessFlags, appInfo);
+    return fieldVisibility != ConstraintWithTarget.NEVER;
   }
 
   private Map<DexField, Set<DexEncodedMethod>> mergeFieldAccessContexts(
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 451b2cb..a19c0d5 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -31,7 +31,7 @@
 import com.android.tools.r8.graph.PresortedComparable;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.MethodPoolCollection;
 import com.android.tools.r8.ir.optimize.MethodPoolCollection.MethodPool;
 import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
@@ -1486,13 +1486,13 @@
     // that we always return true here in these cases.
     if (method.getCode().isJarCode()) {
       JarCode jarCode = method.getCode().asJarCode();
-      Constraint constraint =
+      ConstraintWithTarget constraint =
           jarCode.computeInliningConstraint(
               method,
               appInfo,
               new SingleTypeMapperGraphLense(method.method.holder, invocationContext),
               invocationContext);
-      return constraint == Constraint.NEVER;
+      return constraint == ConstraintWithTarget.NEVER;
     }
     // TODO(christofferqa): For non-jar code we currently cannot guarantee that markForceInline()
     // will succeed.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstraintWithTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstraintWithTargetTest.java
new file mode 100644
index 0000000..f3dbe46
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstraintWithTargetTest.java
@@ -0,0 +1,144 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.optimize;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ConstraintWithTargetTest {
+  private static DexItemFactory factory;
+  private static AppInfoWithSubtyping appInfo;
+
+  @BeforeClass
+  public static void makeAppInfo() throws Exception {
+    InternalOptions options = new InternalOptions();
+    DexApplication application =
+        new ApplicationReader(
+                AndroidApp.builder()
+                    .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
+                    .build(),
+                options,
+                new Timing(ConstraintWithTargetTest.class.getName()))
+            .read()
+            .toDirect();
+    factory = options.itemFactory;
+    appInfo = new AppInfoWithSubtyping(application);
+  }
+
+  private ConstraintWithTarget never() {
+    return ConstraintWithTarget.NEVER;
+  }
+
+  private ConstraintWithTarget always() {
+    return ConstraintWithTarget.ALWAYS;
+  }
+
+  private ConstraintWithTarget element(Constraint constraint, DexType type) {
+    return new ConstraintWithTarget(constraint, type);
+  }
+
+  private ConstraintWithTarget meet(ConstraintWithTarget e1, ConstraintWithTarget e2) {
+    return ConstraintWithTarget.min(e1, e2, appInfo);
+  }
+
+  @Test
+  public void meetNeverIsNever() {
+    assertEquals(never(),
+        meet(never(), always()));
+    assertEquals(never(),
+        meet(always(), never()));
+    assertEquals(never(),
+        meet(never(), element(Constraint.SAMECLASS, factory.objectType)));
+  }
+
+  @Test
+  public void meetAlwaysIsUnit() {
+    ConstraintWithTarget o = element(Constraint.SUBCLASS, factory.objectType);
+    assertEquals(o,
+        meet(always(), o));
+    assertEquals(o,
+        meet(o, always()));
+  }
+
+  @Test
+  public void withSameTarget() {
+    DexType s = factory.createType("Ljava/lang/String;");
+    ConstraintWithTarget c0 = element(Constraint.SAMECLASS, s);
+    ConstraintWithTarget c1 = element(Constraint.PACKAGE, s);
+    ConstraintWithTarget c2 = element(Constraint.SUBCLASS, s);
+    assertEquals(c0,
+        meet(c1, c0));
+    assertEquals(c0,
+        meet(c0, c2));
+    assertEquals(c1,
+        meet(c2, c1));
+  }
+
+  @Test
+  public void withDifferentTarget() {
+    DexType s = factory.createType("Ljava/lang/String;");
+    DexType b = factory.createType("Ljava/lang/StringBuilder;");
+    ConstraintWithTarget c1 = element(Constraint.SAMECLASS, s);
+    ConstraintWithTarget c2 = element(Constraint.SAMECLASS, b);
+    assertEquals(never(),
+        meet(c1, c2));
+
+    ConstraintWithTarget c0 = element(Constraint.PACKAGE, factory.objectType);
+    assertEquals(c1,
+        meet(c0, c1));
+    assertEquals(c2,
+        meet(c0, c2));
+
+    c0 = element(Constraint.SUBCLASS, factory.objectType);
+    assertEquals(c1,
+        meet(c0, c1));
+    assertEquals(c2,
+        meet(c0, c2));
+
+    c1 = element(Constraint.PACKAGE, s);
+    c2 = element(Constraint.PACKAGE, b);
+    assertEquals(c1,
+        meet(c0, c1));
+    assertEquals(c2,
+        meet(c0, c2));
+    assertEquals(c1,
+        meet(c1, c2));
+    assertEquals(c2,
+        meet(c2, c1));
+
+    DexType t = factory.createType("Ljava/lang/reflect/Type;");
+    DexType c = factory.createType("Ljava/lang/Class;");
+    c1 = element(Constraint.SUBCLASS, t);
+    c2 = element(Constraint.SUBCLASS, c);
+    assertEquals(c2,
+        meet(c1, c2));
+    assertEquals(c2,
+        meet(c2, c1));
+  }
+
+
+  @Test
+  public void b111080693() {
+    ConstraintWithTarget c1 =
+        element(Constraint.SUBCLASS, factory.createType("Ljava/lang/Class;"));
+    ConstraintWithTarget c2 =
+        element(Constraint.PACKAGE, factory.createType("Ljava/lang/reflect/Type;"));
+    assertEquals(never(),
+        meet(c1, c2));
+  }
+
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java b/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
index d424c39..f079016 100644
--- a/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
+++ b/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
@@ -20,13 +20,11 @@
 import com.android.tools.r8.regress.b111080693.b.RecyclerView;
 import com.android.tools.r8.utils.AndroidApp;
 import com.google.common.collect.ImmutableList;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(VmTestRunner.class)
 public class B111080693 extends TestBase {
-  @Ignore("b/111080693")
   @Test
   public void test() throws Exception {
     R8Command.Builder builder = R8Command.builder();