Tue, 14 May 2013 11:11:09 -0700
8012556: Implement lambda methods on interfaces as static
8006140: Javac NPE compiling Lambda expression on initialization expression of static field in interface
Summary: Lambdas occurring in static contexts or those not needing instance information should be generated into static methods. This has long been the case for classes. However, as a work-around to the lack of support for statics on interfaces, interface lambda methods have been generated into default methods. For lambdas in interface static contexts (fields and static methods) this causes an NPE in javac because there is no 'this'. MethodHandles now support static methods on interfaces. This changeset allows lambda methods to be generated as static interface methods. An existing bug in Hotspot (8013875) is exposed in a test when the "-esa" flag is used. This test and another test that already exposed this bug have been marked with @ignore.
Reviewed-by: mcimadamore
1 /*
2 * Copyright (c) 2011, 2013, 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 */
24 /*
25 * @test
26 * @bug 7115052
27 * @bug 8003280 8006694
28 * @summary Add lambda tests
29 * Add parser support for method references
30 * temporarily workaround combo tests are causing time out in several platforms
31 * @library ../lib
32 * @build JavacTestingAbstractThreadedTest
33 * @run main/othervm MethodReferenceParserTest
34 */
36 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
37 // see JDK-8006746
39 import java.net.URI;
40 import java.util.Arrays;
41 import javax.tools.Diagnostic;
42 import javax.tools.JavaFileObject;
43 import javax.tools.SimpleJavaFileObject;
44 import com.sun.source.util.JavacTask;
46 public class MethodReferenceParserTest
47 extends JavacTestingAbstractThreadedTest
48 implements Runnable {
50 enum ReferenceKind {
51 METHOD_REF("#Q::#Gm"),
52 CONSTRUCTOR_REF("#Q::#Gnew"),
53 FALSE_REF("min < max"),
54 ERR_SUPER("#Q::#Gsuper"),
55 ERR_METH0("#Q::#Gm()"),
56 ERR_METH1("#Q::#Gm(X)"),
57 ERR_CONSTR0("#Q::#Gnew()"),
58 ERR_CONSTR1("#Q::#Gnew(X)");
60 String referenceTemplate;
62 ReferenceKind(String referenceTemplate) {
63 this.referenceTemplate = referenceTemplate;
64 }
66 String getReferenceString(QualifierKind qk, GenericKind gk) {
67 return referenceTemplate
68 .replaceAll("#Q", qk.qualifier)
69 .replaceAll("#G", gk.typeParameters);
70 }
72 boolean erroneous() {
73 switch (this) {
74 case ERR_SUPER:
75 case ERR_METH0:
76 case ERR_METH1:
77 case ERR_CONSTR0:
78 case ERR_CONSTR1:
79 return true;
80 default: return false;
81 }
82 }
83 }
85 enum ContextKind {
86 ASSIGN("SAM s = #E;"),
87 METHOD("m(#E, i);");
89 String contextTemplate;
91 ContextKind(String contextTemplate) {
92 this.contextTemplate = contextTemplate;
93 }
95 String contextString(ExprKind ek, ReferenceKind rk, QualifierKind qk,
96 GenericKind gk, SubExprKind sk) {
97 return contextTemplate.replaceAll("#E", ek.expressionString(rk, qk, gk, sk));
98 }
99 }
101 enum GenericKind {
102 NONE(""),
103 ONE("<X>"),
104 TWO("<X,Y>");
106 String typeParameters;
108 GenericKind(String typeParameters) {
109 this.typeParameters = typeParameters;
110 }
111 }
113 enum QualifierKind {
114 THIS("this"),
115 SUPER("super"),
116 NEW("new Foo()"),
117 METHOD("m()"),
118 FIELD("a.f"),
119 UBOUND_SIMPLE("A"),
120 UNBOUND_ARRAY1("int[]"),
121 UNBOUND_ARRAY2("A<G>[][]"),
122 UNBOUND_GENERIC1("A<X>"),
123 UNBOUND_GENERIC2("A<X, Y>"),
124 UNBOUND_GENERIC3("A<? extends X, ? super Y>"),
125 UNBOUND_GENERIC4("A<int[], short[][]>"),
126 NESTED_GENERIC1("A<A<X,Y>, A<X,Y>>"),
127 NESTED_GENERIC2("A<A<A<X,Y>,A<X,Y>>, A<A<X,Y>,A<X,Y>>>");
129 String qualifier;
131 QualifierKind(String qualifier) {
132 this.qualifier = qualifier;
133 }
134 }
136 enum ExprKind {
137 NONE("#R::S"),
138 SINGLE_PAREN1("(#R#S)"),
139 SINGLE_PAREN2("(#R)#S"),
140 DOUBLE_PAREN1("((#R#S))"),
141 DOUBLE_PAREN2("((#R)#S)"),
142 DOUBLE_PAREN3("((#R))#S");
144 String expressionTemplate;
146 ExprKind(String expressionTemplate) {
147 this.expressionTemplate = expressionTemplate;
148 }
150 String expressionString(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk) {
151 return expressionTemplate
152 .replaceAll("#R", rk.getReferenceString(qk, gk))
153 .replaceAll("#S", sk.subExpression);
154 }
155 }
157 enum SubExprKind {
158 NONE(""),
159 SELECT_FIELD(".f"),
160 SELECT_METHOD(".f()"),
161 SELECT_NEW(".new Foo()"),
162 POSTINC("++"),
163 POSTDEC("--");
165 String subExpression;
167 SubExprKind(String subExpression) {
168 this.subExpression = subExpression;
169 }
170 }
172 public static void main(String... args) throws Exception {
173 for (ReferenceKind rk : ReferenceKind.values()) {
174 for (QualifierKind qk : QualifierKind.values()) {
175 for (GenericKind gk : GenericKind.values()) {
176 for (SubExprKind sk : SubExprKind.values()) {
177 for (ExprKind ek : ExprKind.values()) {
178 for (ContextKind ck : ContextKind.values()) {
179 pool.execute(new MethodReferenceParserTest(rk, qk, gk, sk, ek, ck));
180 }
181 }
182 }
183 }
184 }
185 }
187 checkAfterExec();
188 }
190 ReferenceKind rk;
191 QualifierKind qk;
192 GenericKind gk;
193 SubExprKind sk;
194 ExprKind ek;
195 ContextKind ck;
196 JavaSource source;
197 DiagnosticChecker diagChecker;
199 MethodReferenceParserTest(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk, ExprKind ek, ContextKind ck) {
200 this.rk = rk;
201 this.qk = qk;
202 this.gk = gk;
203 this.sk = sk;
204 this.ek = ek;
205 this.ck = ck;
206 this.source = new JavaSource();
207 this.diagChecker = new DiagnosticChecker();
208 }
210 class JavaSource extends SimpleJavaFileObject {
212 String template = "class Test {\n" +
213 " void test() {\n" +
214 " #C\n" +
215 " }" +
216 "}";
218 String source;
220 public JavaSource() {
221 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
222 source = template.replaceAll("#C", ck.contextString(ek, rk, qk, gk, sk));
223 }
225 @Override
226 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
227 return source;
228 }
229 }
231 @Override
232 public void run() {
233 JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
234 null, null, Arrays.asList(source));
235 try {
236 ct.parse();
237 } catch (Throwable ex) {
238 processException(ex);
239 return;
240 }
241 check();
242 }
244 void check() {
245 checkCount.incrementAndGet();
247 if (diagChecker.errorFound != rk.erroneous()) {
248 throw new Error("invalid diagnostics for source:\n" +
249 source.getCharContent(true) +
250 "\nFound error: " + diagChecker.errorFound +
251 "\nExpected error: " + rk.erroneous());
252 }
253 }
255 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
257 boolean errorFound;
259 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
260 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
261 errorFound = true;
262 }
263 }
264 }
266 }