< prev index next >

src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
--- 1,7 ---
  /*
!  * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

*** 22,10 ***
--- 22,11 ---
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package java.lang.invoke;
  
+ import jdk.internal.value.PrimitiveClass;
  import sun.invoke.util.Wrapper;
  
  import java.lang.reflect.Modifier;
  
  import static java.lang.invoke.MethodHandleInfo.*;

*** 197,10 ***
--- 198,17 ---
              throw new LambdaConversionException(String.format(
                      "%s is not an interface",
                      interfaceClass.getName()));
          }
  
+         if (interfaceClass.isIdentity() || interfaceClass.isValue()) {
+             throw new LambdaConversionException(String.format(
+                     "%s is %s interface",
+                     interfaceClass.getName(),
+                     interfaceClass.isIdentity() ? "an identity" : "a value"));
+         }
+ 
          for (Class<?> c : altInterfaces) {
              if (!c.isInterface()) {
                  throw new LambdaConversionException(String.format(
                          "%s is not an interface",
                          c.getName()));

*** 266,14 ***
                  samStart = capturedArity;
                  receiverClass = factoryType.parameterType(0);
              }
  
              // check receiver type
!             if (!implClass.isAssignableFrom(receiverClass)) {
                  throw new LambdaConversionException(
                          String.format("Invalid receiver type %s; not a subtype of implementation type %s",
!                                       receiverClass, implClass));
              }
          } else {
              // no receiver
              capturedStart = 0;
              samStart = capturedArity;
--- 274,14 ---
                  samStart = capturedArity;
                  receiverClass = factoryType.parameterType(0);
              }
  
              // check receiver type
!             if (!PrimitiveClass.asPrimaryType(implClass).isAssignableFrom(PrimitiveClass.asPrimaryType(receiverClass))) {
                  throw new LambdaConversionException(
                          String.format("Invalid receiver type %s; not a subtype of implementation type %s",
!                                       receiverClass.descriptorString(), implClass.descriptorString()));
              }
          } else {
              // no receiver
              capturedStart = 0;
              samStart = capturedArity;

*** 319,11 ***
      /** Validate that the given descriptor's types are compatible with {@code dynamicMethodType} **/
      private void checkDescriptor(MethodType descriptor) throws LambdaConversionException {
          for (int i = 0; i < dynamicMethodType.parameterCount(); i++) {
              Class<?> dynamicParamType = dynamicMethodType.parameterType(i);
              Class<?> descriptorParamType = descriptor.parameterType(i);
!             if (!descriptorParamType.isAssignableFrom(dynamicParamType)) {
                  String msg = String.format("Type mismatch for dynamic parameter %d: %s is not a subtype of %s",
                                             i, dynamicParamType, descriptorParamType);
                  throw new LambdaConversionException(msg);
              }
          }
--- 327,11 ---
      /** Validate that the given descriptor's types are compatible with {@code dynamicMethodType} **/
      private void checkDescriptor(MethodType descriptor) throws LambdaConversionException {
          for (int i = 0; i < dynamicMethodType.parameterCount(); i++) {
              Class<?> dynamicParamType = dynamicMethodType.parameterType(i);
              Class<?> descriptorParamType = descriptor.parameterType(i);
!             if (!PrimitiveClass.asPrimaryType(descriptorParamType).isAssignableFrom(PrimitiveClass.asPrimaryType(dynamicParamType))) {
                  String msg = String.format("Type mismatch for dynamic parameter %d: %s is not a subtype of %s",
                                             i, dynamicParamType, descriptorParamType);
                  throw new LambdaConversionException(msg);
              }
          }

*** 369,16 ***
                  } else {
                      // must be convertible to primitive
                      return !strict;
                  }
              } else {
!                 // both are reference types: fromType should be a superclass of toType.
!                 return !strict || toType.isAssignableFrom(fromType);
              }
          }
      }
  
      /**
       * Check type adaptability for return types --
       * special handling of void type) and parameterized fromType
       * @return True if 'fromType' can be converted to 'toType'
       */
--- 377,48 ---
                  } else {
                      // must be convertible to primitive
                      return !strict;
                  }
              } else {
!                 // primitive types: fromType and toType are types of the same primitive class
!                 // identity types: fromType should be a superclass of toType.
+                 return !strict || canConvert(fromType, toType);
              }
          }
      }
  
+     /**
+      * Tests if {@code fromType} can be converted to {@code toType}
+      * via an identity conversion, via a widening reference conversion or
+      * via primitive class narrowing and widening conversions.
+      * <p>
+      * If {@code fromType} represents a class or interface, this method
+      * returns {@code true} if {@code toType} is the same as,
+      * or is a superclass or superinterface of, {@code fromType}.
+      * <p>
+      * If {@code fromType} and {@code toType} is of the same primitive class,
+      * this method returns {@code true}.
+      * <p>
+      * Otherwise, this method returns {@code false}.
+      *
+      * @param     fromType the {@code Class} object to be converted from
+      * @param     toType the {@code Class} object to be converted to
+      * @return    {@code true} if {@code fromType} can be converted to {@code toType}
+      */
+     private boolean canConvert(Class<?> fromType, Class<?> toType) {
+         if (toType.isAssignableFrom(fromType)) {
+             return true;
+         }
+ 
+         if (fromType.isValue() && toType.isValue()) {
+             // val projection can be converted to ref projection; or vice verse
+             return PrimitiveClass.asPrimaryType(fromType) == PrimitiveClass.asPrimaryType(toType);
+         }
+ 
+         return false;
+     }
+ 
      /**
       * Check type adaptability for return types --
       * special handling of void type) and parameterized fromType
       * @return True if 'fromType' can be converted to 'toType'
       */
< prev index next >