Revert "Cleanup return type checks with arrays."

This reverts commit 59193a6871c3f55190362742b5e495372a28f47d.

Bug: 28313047
Bug: 199056476

Reason for revert: Braino, missing hard failure.

Change-Id: I6b8e4ce1dfa4f4a7d5eb44dfd496ac1a92ce6f85
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index db1940c..23d4de0 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2179,14 +2179,21 @@
               Fail(VERIFY_ERROR_UNRESOLVED_TYPE_CHECK)
                   << " can't resolve returned type '" << return_type << "' or '" << reg_type << "'";
             } else {
+              bool soft_error = false;
               // Check whether arrays are involved. They will show a valid class status, even
               // if their components are erroneous.
               if (reg_type.IsArrayTypes() && return_type.IsArrayTypes()) {
-                if (!return_type.CanAssignArray(reg_type, reg_types_, class_loader_, this)) {
-                  Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning '" << reg_type
-                      << "', but expected from declaration '" << return_type << "'";
+                return_type.CanAssignArray(reg_type, reg_types_, class_loader_, this, &soft_error);
+                if (soft_error) {
+                  Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "array with erroneous component type: "
+                        << reg_type << " vs " << return_type;
                 }
               }
+
+              if (!soft_error) {
+                Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning '" << reg_type
+                    << "', but expected from declaration '" << return_type << "'";
+              }
             }
           }
         }
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 3891f21..5af2d4b 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -1035,10 +1035,18 @@
 bool RegType::CanAssignArray(const RegType& src,
                              RegTypeCache& reg_types,
                              Handle<mirror::ClassLoader> class_loader,
-                             MethodVerifier* verifier) const {
-  DCHECK(!IsUnresolvedMergedReference());
-  DCHECK(!src.IsUnresolvedMergedReference());
+                             MethodVerifier* verifier,
+                             bool* soft_error) const {
   if (!IsArrayTypes() || !src.IsArrayTypes()) {
+    *soft_error = false;
+    return false;
+  }
+
+  if (IsUnresolvedMergedReference() || src.IsUnresolvedMergedReference()) {
+    // An unresolved array type means that it's an array of some reference type. Reference arrays
+    // can never be assigned to primitive-type arrays, and vice versa. So it is a soft error if
+    // both arrays are reference arrays, otherwise a hard error.
+    *soft_error = IsObjectArrayTypes() && src.IsObjectArrayTypes();
     return false;
   }
 
@@ -1050,20 +1058,25 @@
   }
   if (cmp1.IsUnresolvedTypes()) {
     if (cmp2.IsIntegralTypes() || cmp2.IsFloatTypes() || cmp2.IsArrayTypes()) {
+      *soft_error = false;
       return false;
     }
+    *soft_error = true;
     return false;
   }
   if (cmp2.IsUnresolvedTypes()) {
     if (cmp1.IsIntegralTypes() || cmp1.IsFloatTypes() || cmp1.IsArrayTypes()) {
+      *soft_error = false;
       return false;
     }
+    *soft_error = true;
     return false;
   }
   if (!cmp1.IsArrayTypes() || !cmp2.IsArrayTypes()) {
+    *soft_error = false;
     return false;
   }
-  return cmp1.CanAssignArray(cmp2, reg_types, class_loader, verifier);
+  return cmp1.CanAssignArray(cmp2, reg_types, class_loader, verifier, soft_error);
 }
 
 const NullType* NullType::CreateInstance(ObjPtr<mirror::Class> klass,
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 5245591..e8a7a80 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -222,11 +222,15 @@
   // Can this array type potentially be assigned by src.
   // This function is necessary as array types are valid even if their components types are not,
   // e.g., when they component type could not be resolved. The function will return true iff the
-  // types assignable. It will return false otherwise.
+  // types are assignable. It will return false otherwise. In case of return=false, soft_error
+  // will be set to true iff the assignment test failure should be treated as a soft-error, i.e.,
+  // when both array types have the same 'depth' and the 'final' component types may be assignable
+  // (both are reference types).
   bool CanAssignArray(const RegType& src,
                       RegTypeCache& reg_types,
                       Handle<mirror::ClassLoader> class_loader,
-                      MethodVerifier* verifier) const
+                      MethodVerifier* verifier,
+                      bool* soft_error) const
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't