Skip to content

Commit e650bdf

Browse files
author
Vicente Romero
committed
8332507: compilation result depends on compilation order
Reviewed-by: mcimadamore
1 parent e4fbb15 commit e650bdf

File tree

2 files changed

+229
-2
lines changed

2 files changed

+229
-2
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,8 +590,21 @@ Type classSigToType() {
590590
ClassSymbol t = enterClass(readName(signatureBuffer,
591591
startSbp,
592592
sbp - startSbp));
593-
outer = new ClassType(outer, sigToTypes('>'), t) {
593+
List<Type> actuals = sigToTypes('>');
594+
List<Type> formals = ((ClassType)t.type.tsym.type).typarams_field;
595+
if (formals != null) {
596+
if (actuals.isEmpty())
597+
actuals = formals;
598+
}
599+
/* actualsCp is final as it will be captured by the inner class below. We could avoid defining
600+
* this additional local variable and depend on field ClassType::typarams_field which `actuals` is
601+
* assigned to but then we would have a dependendy on the internal representation of ClassType which
602+
* could change in the future
603+
*/
604+
final List<Type> actualsCp = actuals;
605+
outer = new ClassType(outer, actuals, t) {
594606
boolean completed = false;
607+
boolean typeArgsSet = false;
595608
@Override @DefinedBy(Api.LANGUAGE_MODEL)
596609
public Type getEnclosingType() {
597610
if (!completed) {
@@ -621,7 +634,27 @@ public Type getEnclosingType() {
621634
public void setEnclosingType(Type outer) {
622635
throw new UnsupportedOperationException();
623636
}
624-
};
637+
638+
@Override
639+
public List<Type> getTypeArguments() {
640+
if (!typeArgsSet) {
641+
typeArgsSet = true;
642+
List<Type> formalsCp = ((ClassType)t.type.tsym.type).typarams_field;
643+
if (formalsCp != null && !formalsCp.isEmpty()) {
644+
if (actualsCp.length() == formalsCp.length()) {
645+
List<Type> a = actualsCp;
646+
List<Type> f = formalsCp;
647+
while (a.nonEmpty()) {
648+
a.head = a.head.withTypeVar(f.head);
649+
a = a.tail;
650+
f = f.tail;
651+
}
652+
}
653+
}
654+
}
655+
return super.getTypeArguments();
656+
}
657+
};
625658
switch (signature[sigp++]) {
626659
case ';':
627660
if (sigp < siglimit && signature[sigp] == '.') {
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* Copyright (c) 2024, 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 8332507
27+
* @summary compilation result depends on compilation order
28+
* @library /tools/lib
29+
* @modules
30+
* jdk.compiler/com.sun.tools.javac.code
31+
* jdk.compiler/com.sun.tools.javac.util
32+
* jdk.compiler/com.sun.tools.javac.api
33+
* jdk.compiler/com.sun.tools.javac.file
34+
* jdk.compiler/com.sun.tools.javac.main
35+
* jdk.jdeps/com.sun.tools.classfile
36+
* @build toolbox.ToolBox toolbox.JavacTask
37+
* @run main WildcardBoundsNotReadFromClassFileTest
38+
*/
39+
40+
import java.nio.file.Path;
41+
import java.nio.file.Paths;
42+
43+
import com.sun.tools.javac.code.Flags;
44+
import com.sun.tools.javac.util.Assert;
45+
import com.sun.tools.classfile.ClassFile;
46+
47+
import toolbox.TestRunner;
48+
import toolbox.ToolBox;
49+
import toolbox.JavacTask;
50+
import toolbox.Task;
51+
52+
public class WildcardBoundsNotReadFromClassFileTest extends TestRunner {
53+
ToolBox tb = new ToolBox();
54+
55+
public WildcardBoundsNotReadFromClassFileTest() {
56+
super(System.err);
57+
}
58+
59+
protected void runTests() throws Exception {
60+
runTests(m -> new Object[] { Paths.get(m.getName()) });
61+
}
62+
63+
Path[] findJavaFiles(Path... paths) throws Exception {
64+
return tb.findJavaFiles(paths);
65+
}
66+
67+
public static void main(String... args) throws Exception {
68+
new WildcardBoundsNotReadFromClassFileTest().runTests();
69+
}
70+
71+
@Test
72+
public void testSeparateCompilation1(Path base) throws Exception {
73+
Path src = base.resolve("src");
74+
tb.writeJavaFiles(src,
75+
"""
76+
import java.util.List;
77+
public class A {
78+
static void of(List<Attribute<?>> attributes) {}
79+
}
80+
class Attribute<T extends Attribute<T>> {}
81+
class A1 extends Attribute<A1> {}
82+
""");
83+
Path classes = base.resolve("classes");
84+
tb.createDirectories(classes);
85+
86+
// let's compile A.java first
87+
new toolbox.JavacTask(tb)
88+
.outdir(classes)
89+
.files(findJavaFiles(src))
90+
.run()
91+
.writeAll();
92+
93+
// now class Test with the rest in the classpath
94+
tb.writeJavaFiles(src,
95+
"""
96+
import java.util.List;
97+
import java.util.stream.*;
98+
public class Test {
99+
void m(Stream<Attribute<?>> stream, boolean cond) {
100+
A.of(stream.map(atr -> cond ? (A1) atr : atr).toList());
101+
}
102+
}
103+
""");
104+
new toolbox.JavacTask(tb)
105+
.outdir(classes)
106+
.options("-cp", classes.toString())
107+
.files(src.resolve("Test.java"))
108+
.run()
109+
.writeAll();
110+
}
111+
112+
@Test
113+
public void testSeparateCompilation2(Path base) throws Exception {
114+
// this test uses nested classes
115+
Path src = base.resolve("src");
116+
tb.writeJavaFiles(src,
117+
"""
118+
import java.util.List;
119+
public class A {
120+
static void of(List<Attribute<?>> attributes) {}
121+
public interface Attribute<A extends Attribute<A>> {
122+
public static final class A1 implements Attribute<A1> {}
123+
}
124+
}
125+
""");
126+
Path classes = base.resolve("classes");
127+
tb.createDirectories(classes);
128+
129+
// let's compile A.java first
130+
new toolbox.JavacTask(tb)
131+
.outdir(classes)
132+
.files(findJavaFiles(src))
133+
.run()
134+
.writeAll();
135+
136+
// now class Test with the rest in the classpath
137+
tb.writeJavaFiles(src,
138+
"""
139+
import java.util.List;
140+
import java.util.stream.*;
141+
public class Test {
142+
void m(Stream<A.Attribute<?>> stream, boolean cond) {
143+
A.of(stream.map(atr -> cond ? (A.Attribute.A1) atr : atr).toList());
144+
}
145+
}
146+
""");
147+
new toolbox.JavacTask(tb)
148+
.outdir(classes)
149+
.options("-cp", classes.toString())
150+
.files(src.resolve("Test.java"))
151+
.run()
152+
.writeAll();
153+
}
154+
155+
@Test
156+
public void testSeparateCompilation3(Path base) throws Exception {
157+
// this test uses nested classes too
158+
Path src = base.resolve("src");
159+
tb.writeJavaFiles(src,
160+
"""
161+
import java.util.Map;
162+
abstract class A {
163+
interface I<X extends String> {}
164+
abstract void f(Map<String, I<?>> i);
165+
}
166+
""");
167+
Path classes = base.resolve("classes");
168+
tb.createDirectories(classes);
169+
170+
// let's compile A.java first
171+
new toolbox.JavacTask(tb)
172+
.outdir(classes)
173+
.files(findJavaFiles(src))
174+
.run()
175+
.writeAll();
176+
177+
// now class B with the rest in the classpath
178+
tb.writeJavaFiles(src,
179+
"""
180+
import java.util.Map;
181+
public class B {
182+
void f(A a, Map<String, A.I<? extends String>> x) {
183+
a.f(x);
184+
}
185+
}
186+
""");
187+
new toolbox.JavacTask(tb)
188+
.outdir(classes)
189+
.options("-cp", classes.toString())
190+
.files(src.resolve("B.java"))
191+
.run()
192+
.writeAll();
193+
}
194+
}

0 commit comments

Comments
 (0)