Always print a (unknown) reason for not inlining

Bug: 142108662
Change-Id: Ib0fee5b77e01b51242114a03fd50dc5d7497e2f2
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 9944273..56bfebb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -51,6 +51,7 @@
 import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.MutableCallSiteOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.UpdatableMethodOptimizationInfo;
+import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.FieldAccessorSourceCode;
@@ -347,41 +348,77 @@
   }
 
   public boolean isInliningCandidate(
-      DexEncodedMethod container, Reason inliningReason, AppInfoWithSubtyping appInfo) {
+      DexEncodedMethod container,
+      Reason inliningReason,
+      AppInfoWithSubtyping appInfo,
+      WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
     checkIfObsolete();
-    return isInliningCandidate(container.method.holder, inliningReason, appInfo);
+    return isInliningCandidate(
+        container.method.holder, inliningReason, appInfo, whyAreYouNotInliningReporter);
   }
 
   public boolean isInliningCandidate(
-      DexType containerType, Reason inliningReason, AppInfoWithSubtyping appInfo) {
+      DexType containerType,
+      Reason inliningReason,
+      AppInfoWithSubtyping appInfo,
+      WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
     checkIfObsolete();
     if (isClassInitializer()) {
       // This will probably never happen but never inline a class initializer.
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
+
     if (inliningReason == Reason.FORCE) {
       // Make sure we would be able to inline this normally.
-      if (!isInliningCandidate(containerType, Reason.SIMPLE, appInfo)) {
+      if (!isInliningCandidate(
+          containerType, Reason.SIMPLE, appInfo, whyAreYouNotInliningReporter)) {
         // If not, raise a flag, because some optimizations that depend on force inlining would
         // silently produce an invalid code, which is worse than an internal error.
         throw new InternalCompilerError("FORCE inlining on non-inlinable: " + toSourceString());
       }
       return true;
     }
+
     // TODO(b/128967328): inlining candidate should satisfy all states if multiple states are there.
     switch (compilationState) {
       case PROCESSED_INLINING_CANDIDATE_ANY:
         return true;
+
       case PROCESSED_INLINING_CANDIDATE_SUBCLASS:
-        return appInfo.isSubtype(containerType, method.holder);
-      case PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE:
-        return containerType.isSamePackage(method.holder);
-      case PROCESSED_INLINING_CANDIDATE_SAME_NEST:
-        return NestUtils.sameNest(containerType, method.holder, appInfo);
-      case PROCESSED_INLINING_CANDIDATE_SAME_CLASS:
-        return containerType == method.holder;
-      default:
+        if (appInfo.isSubtype(containerType, method.holder)) {
+          return true;
+        }
+        whyAreYouNotInliningReporter.reportUnknownReason();
         return false;
+
+      case PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE:
+        if (containerType.isSamePackage(method.holder)) {
+          return true;
+        }
+        whyAreYouNotInliningReporter.reportUnknownReason();
+        return false;
+
+      case PROCESSED_INLINING_CANDIDATE_SAME_NEST:
+        if (NestUtils.sameNest(containerType, method.holder, appInfo)) {
+          return true;
+        }
+        whyAreYouNotInliningReporter.reportUnknownReason();
+        return false;
+
+      case PROCESSED_INLINING_CANDIDATE_SAME_CLASS:
+        if (containerType == method.holder) {
+          return true;
+        }
+        whyAreYouNotInliningReporter.reportUnknownReason();
+        return false;
+
+      case PROCESSED_NOT_INLINING_CANDIDATE:
+        whyAreYouNotInliningReporter.reportUnknownReason();
+        return false;
+
+      default:
+        throw new Unreachable();
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index b408240..d8c4ea7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexClass;
@@ -30,6 +31,7 @@
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.MainDexDirectReferenceTracer;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.IteratorUtils;
 import com.google.common.collect.Sets;
@@ -74,32 +76,53 @@
   }
 
   @Override
+  public boolean isForcedInliningOracle() {
+    return false;
+  }
+
+  @Override
   public void finish() {
     if (Log.ENABLED && info != null) {
       Log.debug(getClass(), info.toString());
     }
   }
 
-  private DexEncodedMethod validateCandidate(InvokeMethod invoke, DexMethod invocationContext) {
-    DexEncodedMethod candidate = invoke.lookupSingleTarget(appView, invocationContext.holder);
-    if ((candidate == null)
-        || (candidate.getCode() == null)
-        || appView.definitionFor(candidate.method.holder).isNotProgramClass()) {
+  private boolean isSingleTargetInvalid(
+      InvokeMethod invoke,
+      DexEncodedMethod singleTarget,
+      WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
+    if (singleTarget == null) {
+      throw new Unreachable();
+    }
+
+    if (!singleTarget.hasCode()) {
       if (info != null) {
         info.exclude(invoke, "No inlinee");
       }
-      return null;
+      whyAreYouNotInliningReporter.reportUnknownReason();
+      return true;
     }
+
+    if (appView.definitionFor(singleTarget.method.holder).isNotProgramClass()) {
+      if (info != null) {
+        info.exclude(invoke, "No inlinee");
+      }
+      whyAreYouNotInliningReporter.reportUnknownReason();
+      return true;
+    }
+
     // Ignore the implicit receiver argument.
     int numberOfArguments =
-        invoke.arguments().size() - (invoke.isInvokeMethodWithReceiver() ? 1 : 0);
-    if (numberOfArguments != candidate.method.getArity()) {
+        invoke.arguments().size() - BooleanUtils.intValue(invoke.isInvokeMethodWithReceiver());
+    if (numberOfArguments != singleTarget.method.getArity()) {
       if (info != null) {
         info.exclude(invoke, "Argument number mismatch");
       }
-      return null;
+      whyAreYouNotInliningReporter.reportUnknownReason();
+      return true;
     }
-    return candidate;
+
+    return false;
   }
 
   private Reason computeInliningReason(DexEncodedMethod target) {
@@ -133,7 +156,8 @@
       InvokeStatic invoke,
       DexEncodedMethod method,
       DexEncodedMethod target,
-      ClassInitializationAnalysis classInitializationAnalysis) {
+      ClassInitializationAnalysis classInitializationAnalysis,
+      WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
     // Only proceed with inlining a static invoke if:
     // - the holder for the target is a subtype of the holder for the method,
     // - the target method always triggers class initialization of its holder before any other side
@@ -172,7 +196,12 @@
     //
     // For simplicity, we are conservative and consider all interfaces, not only the ones with
     // default methods.
-    return !clazz.classInitializationMayHaveSideEffects(appView);
+    if (!clazz.classInitializationMayHaveSideEffects(appView)) {
+      return true;
+    }
+
+    whyAreYouNotInliningReporter.reportUnknownReason();
+    return false;
   }
 
   private synchronized boolean isDoubleInliningTarget(DexEncodedMethod candidate) {
@@ -181,9 +210,13 @@
         && candidate.getCode().estimatedSizeForInliningAtMost(10);
   }
 
-  private boolean passesInliningConstraints(InvokeMethod invoke, DexEncodedMethod candidate,
-      Reason reason) {
+  private boolean passesInliningConstraints(
+      InvokeMethod invoke,
+      DexEncodedMethod candidate,
+      Reason reason,
+      WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
     if (candidate.getOptimizationInfo().neverInline()) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -192,6 +225,7 @@
     if (method.isInstanceInitializer()
         && appView.options().isGeneratingClassFiles()
         && reason != Reason.FORCE) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -202,6 +236,7 @@
       if (info != null) {
         info.exclude(invoke, "direct recursion");
       }
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -214,6 +249,7 @@
       if (info != null) {
         info.exclude(invoke, "is processed in parallel");
       }
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -221,11 +257,13 @@
     if (options.featureSplitConfiguration != null
         && !options.featureSplitConfiguration.inSameFeatureOrBase(
             candidate.method, method.method)) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
     if (options.testing.validInliningReasons != null
         && !options.testing.validInliningReasons.contains(reason)) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -234,6 +272,7 @@
       if (info != null) {
         info.exclude(invoke, "target does not have right access");
       }
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -245,10 +284,12 @@
       if (info != null) {
         info.exclude(invoke, "Do not inline target if method holder is an interface class");
       }
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
     if (holder.isNotProgramClass()) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -257,6 +298,7 @@
       if (info != null) {
         info.exclude(invoke, "target is synchronized");
       }
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -272,11 +314,13 @@
           if (info != null) {
             info.exclude(invoke, "target is not ready for double inlining");
           }
+          whyAreYouNotInliningReporter.reportUnknownReason();
           return false;
         }
       }
     } else if (reason == Reason.SIMPLE
         && !satisfiesRequirementsForSimpleInlining(invoke, candidate)) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return false;
     }
 
@@ -289,6 +333,7 @@
         if (info != null) {
           info.exclude(invoke, "target has references beyond main dex");
         }
+        whyAreYouNotInliningReporter.reportUnknownReason();
         return false;
       }
       // Allow inlining into the classes in the main dex dependent set without restrictions.
@@ -348,13 +393,17 @@
       DexEncodedMethod singleTarget,
       DexMethod invocationContext,
       WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
-    DexEncodedMethod candidate = validateCandidate(invoke, invocationContext);
-    if (candidate == null || inliner.isBlackListed(candidate)) {
+    if (isSingleTargetInvalid(invoke, singleTarget, whyAreYouNotInliningReporter)) {
       return null;
     }
 
-    Reason reason = computeInliningReason(candidate);
-    if (!candidate.isInliningCandidate(method, reason, appView.appInfo())) {
+    if (inliner.isBlackListed(singleTarget, whyAreYouNotInliningReporter)) {
+      return null;
+    }
+
+    Reason reason = computeInliningReason(singleTarget);
+    if (!singleTarget.isInliningCandidate(
+        method, reason, appView.appInfo(), whyAreYouNotInliningReporter)) {
       // Abort inlining attempt if the single target is not an inlining candidate.
       if (info != null) {
         info.exclude(invoke, "target is not identified for inlining");
@@ -362,35 +411,38 @@
       return null;
     }
 
-    if (!passesInliningConstraints(invoke, candidate, reason)) {
+    if (!passesInliningConstraints(invoke, singleTarget, reason, whyAreYouNotInliningReporter)) {
       return null;
     }
 
     if (info != null) {
-      info.include(invoke.getType(), candidate);
+      info.include(invoke.getType(), singleTarget);
     }
 
     Value receiver = invoke.getReceiver();
     if (receiver.getTypeLattice().isDefinitelyNull()) {
       // A definitely null receiver will throw an error on call site.
+      whyAreYouNotInliningReporter.reportUnknownReason();
       return null;
     }
-    InlineAction action = new InlineAction(candidate, invoke, reason);
 
+    InlineAction action = new InlineAction(singleTarget, invoke, reason);
     if (receiver.getTypeLattice().isNullable()) {
       assert !receiver.getTypeLattice().isDefinitelyNull();
       // When inlining an instance method call, we need to preserve the null check for the
       // receiver. Therefore, if the receiver may be null and the candidate inlinee does not
       // throw if the receiver is null before any other side effect, then we must synthesize a
       // null check.
-      if (!candidate.getOptimizationInfo().checksNullReceiverBeforeAnySideEffect()) {
+      if (!singleTarget.getOptimizationInfo().checksNullReceiverBeforeAnySideEffect()) {
         InternalOptions options = appView.options();
         if (!options.enableInliningOfInvokesWithNullableReceivers) {
+          whyAreYouNotInliningReporter.reportUnknownReason();
           return null;
         }
         if (!options.nullableReceiverInliningFilter.isEmpty()
             && !options.nullableReceiverInliningFilter.contains(
                 invoke.getInvokedMethod().toSourceString())) {
+          whyAreYouNotInliningReporter.reportUnknownReason();
           return null;
         }
         if (Log.ENABLED && Log.isLoggingEnabledFor(Inliner.class)) {
@@ -403,7 +455,6 @@
         action.setShouldSynthesizeNullCheckForReceiver();
       }
     }
-
     return action;
   }
 
@@ -414,14 +465,18 @@
       DexMethod invocationContext,
       ClassInitializationAnalysis classInitializationAnalysis,
       WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
-    DexEncodedMethod candidate = validateCandidate(invoke, invocationContext);
-    if (candidate == null || inliner.isBlackListed(candidate)) {
+    if (isSingleTargetInvalid(invoke, singleTarget, whyAreYouNotInliningReporter)) {
       return null;
     }
 
-    Reason reason = computeInliningReason(candidate);
+    if (inliner.isBlackListed(singleTarget, whyAreYouNotInliningReporter)) {
+      return null;
+    }
+
+    Reason reason = computeInliningReason(singleTarget);
     // Determine if this should be inlined no matter how big it is.
-    if (!candidate.isInliningCandidate(method, reason, appView.appInfo())) {
+    if (!singleTarget.isInliningCandidate(
+        method, reason, appView.appInfo(), whyAreYouNotInliningReporter)) {
       // Abort inlining attempt if the single target is not an inlining candidate.
       if (info != null) {
         info.exclude(invoke, "target is not identified for inlining");
@@ -430,21 +485,22 @@
     }
 
     // Abort inlining attempt if we can not guarantee class for static target has been initialized.
-    if (!canInlineStaticInvoke(invoke, method, candidate, classInitializationAnalysis)) {
+    if (!canInlineStaticInvoke(
+        invoke, method, singleTarget, classInitializationAnalysis, whyAreYouNotInliningReporter)) {
       if (info != null) {
         info.exclude(invoke, "target is static but we cannot guarantee class has been initialized");
       }
       return null;
     }
 
-    if (!passesInliningConstraints(invoke, candidate, reason)) {
+    if (!passesInliningConstraints(invoke, singleTarget, reason, whyAreYouNotInliningReporter)) {
       return null;
     }
 
     if (info != null) {
-      info.include(invoke.getType(), candidate);
+      info.include(invoke.getType(), singleTarget);
     }
-    return new InlineAction(candidate, invoke, reason);
+    return new InlineAction(singleTarget, invoke, reason);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
index b44e32c..6c93489 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
@@ -39,6 +39,11 @@
   }
 
   @Override
+  public boolean isForcedInliningOracle() {
+    return true;
+  }
+
+  @Override
   public void finish() {}
 
   @Override
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 9b8d8a8..074c6cd 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
@@ -34,12 +34,15 @@
 import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
+import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotInliningReporter;
 import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
+import com.android.tools.r8.kotlin.Kotlin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.MainDexClasses;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ThreadUtils;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -55,6 +58,8 @@
 public class Inliner {
 
   protected final AppView<AppInfoWithLiveness> appView;
+  private final Set<DexMethod> blackList;
+  private final LensCodeRewriter lensCodeRewriter;
   final MainDexClasses mainDexClasses;
 
   // State for inlining methods which are known to be called twice.
@@ -63,34 +68,46 @@
   private final Set<DexEncodedMethod> doubleInlineSelectedTargets = Sets.newIdentityHashSet();
   private final Map<DexEncodedMethod, DexEncodedMethod> doubleInlineeCandidates = new HashMap<>();
 
-  private final Set<DexMethod> blackList = Sets.newIdentityHashSet();
-  private final LensCodeRewriter lensCodeRewriter;
-
   public Inliner(
       AppView<AppInfoWithLiveness> appView,
       MainDexClasses mainDexClasses,
       LensCodeRewriter lensCodeRewriter) {
+    Kotlin.Intrinsics intrinsics = appView.dexItemFactory().kotlin.intrinsics;
     this.appView = appView;
-    this.mainDexClasses = mainDexClasses;
+    this.blackList = ImmutableSet.of(intrinsics.throwNpe, intrinsics.throwParameterIsNullException);
     this.lensCodeRewriter = lensCodeRewriter;
-    fillInBlackList();
+    this.mainDexClasses = mainDexClasses;
   }
 
-  private void fillInBlackList() {
-    blackList.add(appView.dexItemFactory().kotlin.intrinsics.throwParameterIsNullException);
-    blackList.add(appView.dexItemFactory().kotlin.intrinsics.throwNpe);
-  }
-
-  public boolean isBlackListed(DexEncodedMethod encodedMethod) {
+  boolean isBlackListed(
+      DexEncodedMethod encodedMethod, WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
     DexMethod method = encodedMethod.method;
     if (encodedMethod.getOptimizationInfo().forceInline()
         && appView.appInfo().neverInline.contains(method)) {
       throw new Unreachable();
     }
-    return blackList.contains(appView.graphLense().getOriginalMethodSignature(method))
-        || appView.appInfo().isPinned(method)
-        || appView.appInfo().neverInline.contains(method)
-        || TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(method, appView);
+
+    if (appView.appInfo().isPinned(method)) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
+      return true;
+    }
+
+    if (blackList.contains(appView.graphLense().getOriginalMethodSignature(method))) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
+      return true;
+    }
+
+    if (appView.appInfo().neverInline.contains(method)) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
+      return true;
+    }
+
+    if (TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(method, appView)) {
+      whyAreYouNotInliningReporter.reportUnknownReason();
+      return true;
+    }
+
+    return false;
   }
 
   private ConstraintWithTarget instructionAllowedForInlining(
@@ -738,7 +755,9 @@
           }
 
           WhyAreYouNotInliningReporter whyAreYouNotInliningReporter =
-              WhyAreYouNotInliningReporter.createFor(singleTarget, appView, context);
+              oracle.isForcedInliningOracle()
+                  ? NopWhyAreYouNotInliningReporter.getInstance()
+                  : WhyAreYouNotInliningReporter.createFor(singleTarget, appView, context);
           InlineAction action =
               invoke.computeInlining(
                   singleTarget,
@@ -747,10 +766,10 @@
                   classInitializationAnalysis,
                   whyAreYouNotInliningReporter);
           if (action == null) {
-            // TODO(b/142108662): Enable assertion once reporting is complete.
-            // assert whyAreYouNotInliningReporter.verifyReasonHasBeenReported();
+            assert whyAreYouNotInliningReporter.verifyReasonHasBeenReported();
             continue;
           }
+
           if (!strategy.stillHasBudget(action, whyAreYouNotInliningReporter)) {
             assert whyAreYouNotInliningReporter.verifyReasonHasBeenReported();
             continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index f289b24..2cbc5a0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -19,6 +19,8 @@
  */
 public interface InliningOracle {
 
+  boolean isForcedInliningOracle();
+
   void finish();
 
   // TODO(b/142116551): This should be equivalent to invoke.lookupSingleTarget(appView, context)!
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index bda91af..8930a2a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -39,7 +39,7 @@
 import com.android.tools.r8.ir.optimize.classinliner.ClassInliner.EligibilityStatus;
 import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
-import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotKeepingReporter;
+import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotInliningReporter;
 import com.android.tools.r8.kotlin.KotlinInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ListUtils;
@@ -911,7 +911,7 @@
               defaultOracle.get(),
               method.method,
               ClassInitializationAnalysis.trivial(),
-              NopWhyAreYouNotKeepingReporter.getInstance());
+              NopWhyAreYouNotInliningReporter.getInstance());
       if (inlineAction == null) {
         return false;
       }
@@ -983,7 +983,8 @@
       // return false.
       return true;
     }
-    if (!singleTarget.isInliningCandidate(method, Reason.SIMPLE, appView.appInfo())) {
+    if (!singleTarget.isInliningCandidate(
+        method, Reason.SIMPLE, appView.appInfo(), NopWhyAreYouNotInliningReporter.getInstance())) {
       // If `singleTarget` is not an inlining candidate, we won't be able to inline it here.
       //
       // Note that there may be some false negatives here since the method may
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotKeepingReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotKeepingReporter.java
rename to src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
index 1fac475..0858b45 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotKeepingReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
@@ -8,14 +8,14 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InvokeDirect;
 
-public class NopWhyAreYouNotKeepingReporter extends WhyAreYouNotInliningReporter {
+public class NopWhyAreYouNotInliningReporter extends WhyAreYouNotInliningReporter {
 
-  private static final NopWhyAreYouNotKeepingReporter INSTANCE =
-      new NopWhyAreYouNotKeepingReporter();
+  private static final NopWhyAreYouNotInliningReporter INSTANCE =
+      new NopWhyAreYouNotInliningReporter();
 
-  private NopWhyAreYouNotKeepingReporter() {}
+  private NopWhyAreYouNotInliningReporter() {}
 
-  public static NopWhyAreYouNotKeepingReporter getInstance() {
+  public static NopWhyAreYouNotInliningReporter getInstance() {
     return INSTANCE;
   }
 
@@ -27,6 +27,9 @@
       int estimatedNumberOfControlFlowResolutionBlocks, int threshold) {}
 
   @Override
+  public void reportUnknownReason() {}
+
+  @Override
   public void reportUnknownTarget() {}
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
index 039956c..8834ddf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
@@ -21,7 +21,7 @@
       return new WhyAreYouNotInliningReporterImpl(
           callee, context, appView.options().testing.whyAreYouNotInliningConsumer);
     }
-    return NopWhyAreYouNotKeepingReporter.getInstance();
+    return NopWhyAreYouNotInliningReporter.getInstance();
   }
 
   public static void handleInvokeWithUnknownTarget(
@@ -49,6 +49,8 @@
   public abstract void reportPotentialExplosionInExceptionalControlFlowResolutionBlocks(
       int estimatedNumberOfControlFlowResolutionBlocks, int threshold);
 
+  public abstract void reportUnknownReason();
+
   abstract void reportUnknownTarget();
 
   public abstract void reportUnsafeConstructorInliningDueToFinalFieldAssignment(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
index 6fc1f50..6340db4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
@@ -30,8 +30,12 @@
     output.print(callee.method.toSourceString());
     output.print("` was not inlined into `");
     output.print(context.method.toSourceString());
-    output.print("`: ");
-    output.println(reason);
+    if (reason != null) {
+      output.print("`: ");
+      output.println(reason);
+    } else {
+      output.println("`.");
+    }
     reasonHasBeenReported = true;
   }
 
@@ -55,6 +59,12 @@
         threshold);
   }
 
+  // TODO(b/142108662): Always report a meaningful reason.
+  @Override
+  public void reportUnknownReason() {
+    print(null);
+  }
+
   @Override
   public void reportUnknownTarget() {
     print("could not find a single target.");
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
index 16430eb..f500c06 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
@@ -25,6 +25,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.optimize.Inliner.Reason;
+import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotInliningReporter;
+import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
 import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
 import com.android.tools.r8.ir.optimize.lambda.LambdaGroup.LambdaStructureError;
 import com.android.tools.r8.kotlin.Kotlin;
@@ -111,8 +113,11 @@
     //       can safely use a fake one here.
     DexType fakeLambdaGroupType = kotlin.factory.createType(
         "L" + group.getTypePackage() + "-$$LambdaGroup$XXXX;");
+    WhyAreYouNotInliningReporter whyAreYouNotInliningReporter =
+        NopWhyAreYouNotInliningReporter.getInstance();
     for (DexEncodedMethod method : lambda.virtualMethods()) {
-      if (!method.isInliningCandidate(fakeLambdaGroupType, Reason.SIMPLE, appInfo)) {
+      if (!method.isInliningCandidate(
+          fakeLambdaGroupType, Reason.SIMPLE, appInfo, whyAreYouNotInliningReporter)) {
         throw structureError("method " + method.method.toSourceString() +
             " is not inline-able into lambda group class");
       }