diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 104aa220932..e1fad4d7dbb 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -5347,7 +5347,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * {@code (V T A...)} must have at least one {@code A} type, and the default iterator * handle parameter is adjusted to accept the leading {@code A} type, as if by * the {@link MethodHandle#asType asType} conversion method. - * The leading {@code A} type must be {@code Iterable} or a subtype thereof, or an array type. + * The leading {@code A} type must be {@code Iterable} or a subtype thereof. * This conversion step, done at loop construction time, must not throw a {@code WrongMethodTypeException}. * *

@@ -5374,7 +5374,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * V iteratedLoop(A... a...) { * Iterator it = iterator(a...); * V v = init(a...); - * for (T t : it) { + * while (it.hasNext()) { + * T t = it.next(); * v = body(v, t, a...); * } * return v; @@ -5483,49 +5484,59 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); Objects.requireNonNull(body); MethodType bodyType = body.type(); Class returnType = bodyType.returnType(); - List> innerList = bodyType.parameterList(); + List> internalParamList = bodyType.parameterList(); // strip leading V value if present int vsize = (returnType == void.class ? 0 : 1); - if (vsize != 0 && (innerList.size() == 0 || innerList.get(0) != returnType)) { + if (vsize != 0 && (internalParamList.size() == 0 || internalParamList.get(0) != returnType)) { // argument list has no "V" => error MethodType expected = bodyType.insertParameterTypes(0, returnType); throw misMatchedTypes("body function", bodyType, expected); - } else if (innerList.size() <= vsize) { + } else if (internalParamList.size() <= vsize) { // missing T type => error MethodType expected = bodyType.insertParameterTypes(vsize, Object.class); throw misMatchedTypes("body function", bodyType, expected); } - //Class elementType = innerList.get(vsize); // do not need this - List> outerList = innerList.subList(vsize + 1, innerList.size()); - if (outerList.isEmpty()) { - // special case; take lists from iterator handle - outerList = ((iterator != null) - ? iterator.type().parameterList() - : Arrays.asList(Iterable.class)); - innerList = bodyType.insertParameterTypes(vsize + 1, outerList).parameterList(); - } + List> externalParamList = internalParamList.subList(vsize + 1, internalParamList.size()); + Class iterableType = null; if (iterator != null) { + // special case; if the body handle only declares V and T then + // the external parameter list is obtained from iterator handle + if (externalParamList.isEmpty()) { + externalParamList = iterator.type().parameterList(); + } MethodType itype = iterator.type(); if (!Iterator.class.isAssignableFrom(itype.returnType())) { throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type"); } - if (!itype.effectivelyIdenticalParameters(0, outerList)) { - MethodType expected = methodType(itype.returnType(), outerList); + if (!itype.effectivelyIdenticalParameters(0, externalParamList)) { + MethodType expected = methodType(itype.returnType(), externalParamList); throw misMatchedTypes("iterator parameters", itype, expected); } + } else { + if (externalParamList.isEmpty()) { + // special case; if the iterator handle is null and the body handle + // only declares V and T then the external parameter list consists + // of Iterable + externalParamList = Arrays.asList(Iterable.class); + iterableType = Iterable.class; + } else { + // special case; if the iterator handle is null and the external + // parameter list is not empty then the first parameter must be + // assignable to Iterable + iterableType = externalParamList.get(0); + if (!Iterable.class.isAssignableFrom(iterableType)) { + throw newIllegalArgumentException( + "inferred first loop argument must inherit from Iterable: " + iterableType); + } + } } if (init != null) { MethodType initType = init.type(); if (initType.returnType() != returnType || - !initType.effectivelyIdenticalParameters(0, outerList)) { - throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList)); + !initType.effectivelyIdenticalParameters(0, externalParamList)) { + throw misMatchedTypes("loop initializer", initType, methodType(returnType, externalParamList)); } } - Class iterableType = outerList.isEmpty() ? null : outerList.get(0); - if (iterableType != null && !Iterable.class.isAssignableFrom(iterableType) && !iterableType.isArray()) { - throw newIllegalArgumentException( - "inferred first loop argument must be an array or inherit from Iterable: " + iterableType); - } return iterableType; // help the caller a bit } diff --git a/jdk/test/java/lang/invoke/LoopCombinatorTest.java b/jdk/test/java/lang/invoke/LoopCombinatorTest.java index 1e8b8a8f9a7..fa11affa45c 100644 --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java @@ -33,6 +33,7 @@ * @bug 8153637 * @bug 8154751 * @bug 8154754 + * @bug 8167974 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest */ @@ -800,7 +801,8 @@ public class LoopCombinatorTest { {l_it, l_i, isl_i, ""}, {l_it, null, sl_v, ""}, {li_it, li_i, isli_i, ""}, - {il_it, null, sil_v, "inferred first loop argument must inherit from Iterable: int"}, + {null, null, sil_v, "inferred first loop argument must inherit from Iterable: int"}, + {il_it, null, sil_v, ""}, {li_it, null, sli_v, ""}, {sl_v, null, sl_v, "iteratedLoop first argument must have Iterator return type"}, {li_it, l_it, sl_v,