Skip to content

Commit cf07eae

Browse files
author
Srikanth Adayapalam
committed
8295020: javac emits incorrect code for for-each on an intersection type.
Reviewed-by: mcimadamore
1 parent b3bb3e6 commit cf07eae

File tree

2 files changed

+89
-6
lines changed

2 files changed

+89
-6
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public static Lower instance(Context context) {
9595
private final TypeEnvs typeEnvs;
9696
private final Name dollarAssertionsDisabled;
9797
private final Types types;
98+
private final TransTypes transTypes;
9899
private final boolean debugLower;
99100
private final boolean disableProtectedAccessors; // experimental
100101
private final PkgInfo pkginfoOpt;
@@ -117,6 +118,7 @@ protected Lower(Context context) {
117118
fromString(target.syntheticNameChar() + "assertionsDisabled");
118119

119120
types = Types.instance(context);
121+
transTypes = TransTypes.instance(context);
120122
Options options = Options.instance(context);
121123
debugLower = options.isSet("debuglower");
122124
pkginfoOpt = PkgInfo.get(options);
@@ -3518,16 +3520,15 @@ private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
35183520
syms.iterableType.tsym);
35193521
if (iterableType.getTypeArguments().nonEmpty())
35203522
iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
3521-
Type eType = types.skipTypeVars(tree.expr.type, false);
3522-
tree.expr.type = types.erasure(eType);
3523-
if (eType.isCompound())
3524-
tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
3523+
tree.expr.type = types.erasure(types.skipTypeVars(tree.expr.type, false));
3524+
tree.expr = transTypes.coerce(attrEnv, tree.expr, types.erasure(iterableType));
35253525
Symbol iterator = lookupMethod(tree.expr.pos(),
35263526
names.iterator,
3527-
eType,
3527+
tree.expr.type,
35283528
List.nil());
3529+
Assert.check(types.isSameType(types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)), types.erasure(syms.iteratorType)));
35293530
VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
3530-
types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)),
3531+
types.erasure(syms.iteratorType),
35313532
currentMethodSym);
35323533

35333534
JCStatement init = make.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8295020
27+
* @summary javac emits incorrect code for for-each on an intersection type.
28+
* @run main CovariantIntersectIterator
29+
*/
30+
31+
import java.io.Serializable;
32+
import java.util.Iterator;
33+
34+
public class CovariantIntersectIterator {
35+
36+
public static void main(String... args) {
37+
int npeCount = 0;
38+
try {
39+
// JCEnhancedForLoop.expr's erased type is ALREADY an Iterable
40+
// iterator() comes from expr's erased type (MyIterable) and
41+
// is called using invokevirtual & returns a covariant type (MyIterable.MyIterator)
42+
for (Object s : (MyIterable & Serializable) null) {}
43+
} catch (NullPointerException e) {
44+
npeCount++;
45+
}
46+
try {
47+
// JCEnhancedForLoop.expr's erased type is NOT an Iterable
48+
// iterator() comes from Iterable (expr's erased type casted),
49+
// will be called by invokeinterface and return Iterator
50+
for (Object s : (MyIterableBase & Iterable<Object>) null) {}
51+
} catch (NullPointerException e) {
52+
npeCount++;
53+
}
54+
if (npeCount != 2) {
55+
throw new AssertionError("Expected NPE missing");
56+
}
57+
}
58+
59+
abstract static class MyIterableBase {
60+
public abstract MyIterable.MyIterator iterator();
61+
}
62+
63+
static class MyIterable extends MyIterableBase implements Iterable<Object> {
64+
65+
class MyIterator implements Iterator<Object> {
66+
67+
public boolean hasNext() {
68+
return false;
69+
}
70+
71+
public Object next() {
72+
return null;
73+
}
74+
75+
public void remove() {}
76+
}
77+
78+
public MyIterator iterator() {
79+
return new MyIterator();
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)