test/tools/javac/lambda/FunctionalInterfaceConversionTest.java

Tue, 14 May 2013 11:11:09 -0700

author
rfield
date
Tue, 14 May 2013 11:11:09 -0700
changeset 1752
c09b7234cded
parent 1520
5c956be64b9e
child 2354
b33835c5d96a
permissions
-rw-r--r--

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

mcimadamore@1434 1 /*
vromero@1482 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
mcimadamore@1434 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@1434 4 *
mcimadamore@1434 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@1434 6 * under the terms of the GNU General Public License version 2 only, as
mcimadamore@1434 7 * published by the Free Software Foundation.
mcimadamore@1434 8 *
mcimadamore@1434 9 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@1434 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@1434 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@1434 12 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@1434 13 * accompanied this code).
mcimadamore@1434 14 *
mcimadamore@1434 15 * You should have received a copy of the GNU General Public License version
mcimadamore@1434 16 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@1434 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@1434 18 *
mcimadamore@1434 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mcimadamore@1434 20 * or visit www.oracle.com if you need additional information or have any
mcimadamore@1434 21 * questions.
mcimadamore@1434 22 */
mcimadamore@1434 23
mcimadamore@1434 24 /**
mcimadamore@1434 25 * @test
vromero@1520 26 * @bug 8003280 8004102 8006694
mcimadamore@1434 27 * @summary Add lambda tests
mcimadamore@1434 28 * perform several automated checks in lambda conversion, esp. around accessibility
vromero@1520 29 * temporarily workaround combo tests are causing time out in several platforms
mcimadamore@1434 30 * @author Maurizio Cimadamore
vromero@1482 31 * @library ../lib
vromero@1482 32 * @build JavacTestingAbstractThreadedTest
vromero@1520 33 * @run main/othervm FunctionalInterfaceConversionTest
mcimadamore@1434 34 */
mcimadamore@1434 35
vromero@1520 36 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
vromero@1520 37 // see JDK-8006746
vromero@1520 38
vromero@1482 39 import java.io.IOException;
mcimadamore@1434 40 import java.net.URI;
mcimadamore@1434 41 import java.util.Arrays;
mcimadamore@1434 42 import javax.tools.Diagnostic;
mcimadamore@1434 43 import javax.tools.JavaCompiler;
mcimadamore@1434 44 import javax.tools.JavaFileObject;
mcimadamore@1434 45 import javax.tools.SimpleJavaFileObject;
mcimadamore@1434 46 import javax.tools.ToolProvider;
vromero@1482 47 import com.sun.source.util.JavacTask;
mcimadamore@1434 48
vromero@1482 49 public class FunctionalInterfaceConversionTest
vromero@1482 50 extends JavacTestingAbstractThreadedTest
vromero@1482 51 implements Runnable {
mcimadamore@1434 52
mcimadamore@1434 53 enum PackageKind {
mcimadamore@1434 54 NO_PKG(""),
mcimadamore@1434 55 PKG_A("a");
mcimadamore@1434 56
mcimadamore@1434 57 String pkg;
mcimadamore@1434 58
mcimadamore@1434 59 PackageKind(String pkg) {
mcimadamore@1434 60 this.pkg = pkg;
mcimadamore@1434 61 }
mcimadamore@1434 62
mcimadamore@1434 63 String getPkgDecl() {
mcimadamore@1434 64 return this == NO_PKG ?
mcimadamore@1434 65 "" :
mcimadamore@1434 66 "package " + pkg + ";";
mcimadamore@1434 67 }
mcimadamore@1434 68
mcimadamore@1434 69 String getImportStat() {
mcimadamore@1434 70 return this == NO_PKG ?
mcimadamore@1434 71 "" :
mcimadamore@1434 72 "import " + pkg + ".*;";
mcimadamore@1434 73 }
mcimadamore@1434 74 }
mcimadamore@1434 75
mcimadamore@1434 76 enum SamKind {
mcimadamore@1434 77 CLASS("public class Sam { }"),
mcimadamore@1434 78 ABSTACT_CLASS("public abstract class Sam { }"),
mcimadamore@1434 79 ANNOTATION("public @interface Sam { }"),
mcimadamore@1434 80 ENUM("public enum Sam { }"),
mcimadamore@1434 81 INTERFACE("public interface Sam { \n #METH; \n }");
mcimadamore@1434 82
mcimadamore@1434 83 String sam_str;
mcimadamore@1434 84
mcimadamore@1434 85 SamKind(String sam_str) {
mcimadamore@1434 86 this.sam_str = sam_str;
mcimadamore@1434 87 }
mcimadamore@1434 88
mcimadamore@1434 89 String getSam(String methStr) {
mcimadamore@1434 90 return sam_str.replaceAll("#METH", methStr);
mcimadamore@1434 91 }
mcimadamore@1434 92 }
mcimadamore@1434 93
mcimadamore@1434 94 enum ModifierKind {
mcimadamore@1434 95 PUBLIC("public"),
mcimadamore@1434 96 PACKAGE("");
mcimadamore@1434 97
mcimadamore@1434 98 String modifier_str;
mcimadamore@1434 99
mcimadamore@1434 100 ModifierKind(String modifier_str) {
mcimadamore@1434 101 this.modifier_str = modifier_str;
mcimadamore@1434 102 }
mcimadamore@1434 103
mcimadamore@1434 104 boolean stricterThan(ModifierKind that) {
mcimadamore@1434 105 return this.ordinal() > that.ordinal();
mcimadamore@1434 106 }
mcimadamore@1434 107 }
mcimadamore@1434 108
mcimadamore@1434 109 enum TypeKind {
mcimadamore@1434 110 EXCEPTION("Exception"),
mcimadamore@1434 111 PKG_CLASS("PackageClass");
mcimadamore@1434 112
mcimadamore@1434 113 String typeStr;
mcimadamore@1434 114
mcimadamore@1434 115 private TypeKind(String typeStr) {
mcimadamore@1434 116 this.typeStr = typeStr;
mcimadamore@1434 117 }
mcimadamore@1434 118 }
mcimadamore@1434 119
mcimadamore@1434 120 enum ExprKind {
mcimadamore@1434 121 LAMBDA("x -> null"),
mcimadamore@1434 122 MREF("this::m");
mcimadamore@1434 123
mcimadamore@1434 124 String exprStr;
mcimadamore@1434 125
mcimadamore@1434 126 private ExprKind(String exprStr) {
mcimadamore@1434 127 this.exprStr = exprStr;
mcimadamore@1434 128 }
mcimadamore@1434 129 }
mcimadamore@1434 130
mcimadamore@1434 131 enum MethodKind {
mcimadamore@1434 132 NONE(""),
mcimadamore@1434 133 NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
mcimadamore@1434 134 GENERIC("public abstract <X> #R m(#ARG s) throws #T;");
mcimadamore@1434 135
mcimadamore@1434 136 String methodTemplate;
mcimadamore@1434 137
mcimadamore@1434 138 private MethodKind(String methodTemplate) {
mcimadamore@1434 139 this.methodTemplate = methodTemplate;
mcimadamore@1434 140 }
mcimadamore@1434 141
mcimadamore@1434 142 String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
mcimadamore@1434 143 return methodTemplate.replaceAll("#R", retType.typeStr).
mcimadamore@1434 144 replaceAll("#ARG", argType.typeStr).
mcimadamore@1434 145 replaceAll("#T", thrownType.typeStr);
mcimadamore@1434 146 }
mcimadamore@1434 147 }
mcimadamore@1434 148
mcimadamore@1434 149 public static void main(String[] args) throws Exception {
mcimadamore@1434 150 for (PackageKind samPkg : PackageKind.values()) {
mcimadamore@1434 151 for (ModifierKind modKind : ModifierKind.values()) {
mcimadamore@1434 152 for (SamKind samKind : SamKind.values()) {
mcimadamore@1434 153 for (MethodKind samMeth : MethodKind.values()) {
mcimadamore@1434 154 for (MethodKind clientMeth : MethodKind.values()) {
mcimadamore@1434 155 for (TypeKind retType : TypeKind.values()) {
mcimadamore@1434 156 for (TypeKind argType : TypeKind.values()) {
mcimadamore@1434 157 for (TypeKind thrownType : TypeKind.values()) {
mcimadamore@1434 158 for (ExprKind exprKind : ExprKind.values()) {
vromero@1482 159 pool.execute(
vromero@1482 160 new FunctionalInterfaceConversionTest(
vromero@1482 161 samPkg, modKind, samKind,
vromero@1482 162 samMeth, clientMeth, retType,
vromero@1482 163 argType, thrownType, exprKind));
mcimadamore@1434 164 }
mcimadamore@1434 165 }
mcimadamore@1434 166 }
mcimadamore@1434 167 }
mcimadamore@1434 168 }
mcimadamore@1434 169 }
mcimadamore@1434 170 }
mcimadamore@1434 171 }
mcimadamore@1434 172 }
vromero@1482 173
vromero@1482 174 checkAfterExec(false);
mcimadamore@1434 175 }
mcimadamore@1434 176
mcimadamore@1434 177 PackageKind samPkg;
mcimadamore@1434 178 ModifierKind modKind;
mcimadamore@1434 179 SamKind samKind;
mcimadamore@1434 180 MethodKind samMeth;
mcimadamore@1434 181 MethodKind clientMeth;
mcimadamore@1434 182 TypeKind retType;
mcimadamore@1434 183 TypeKind argType;
mcimadamore@1434 184 TypeKind thrownType;
mcimadamore@1434 185 ExprKind exprKind;
mcimadamore@1434 186 DiagnosticChecker dc;
mcimadamore@1434 187
mcimadamore@1434 188 SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
vromero@1482 189 @Override
mcimadamore@1434 190 public String toString() {
mcimadamore@1434 191 return template.replaceAll("#P", samPkg.getPkgDecl()).
vromero@1482 192 replaceAll("#C", samKind.getSam(
vromero@1482 193 samMeth.getMethod(retType, argType, thrownType)));
mcimadamore@1434 194 }
mcimadamore@1434 195 };
mcimadamore@1434 196
vromero@1482 197 SourceFile pkgClassSourceFile =
vromero@1482 198 new SourceFile("PackageClass.java",
vromero@1482 199 "#P\n #M class PackageClass extends Exception { }") {
vromero@1482 200 @Override
mcimadamore@1434 201 public String toString() {
mcimadamore@1434 202 return template.replaceAll("#P", samPkg.getPkgDecl()).
mcimadamore@1434 203 replaceAll("#M", modKind.modifier_str);
mcimadamore@1434 204 }
mcimadamore@1434 205 };
mcimadamore@1434 206
vromero@1482 207 SourceFile clientSourceFile =
vromero@1482 208 new SourceFile("Client.java",
vromero@1482 209 "#I\n abstract class Client { \n" +
vromero@1482 210 " Sam s = #E;\n" +
vromero@1482 211 " #M \n }") {
vromero@1482 212 @Override
mcimadamore@1434 213 public String toString() {
mcimadamore@1434 214 return template.replaceAll("#I", samPkg.getImportStat())
mcimadamore@1434 215 .replaceAll("#E", exprKind.exprStr)
mcimadamore@1434 216 .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
mcimadamore@1434 217 }
mcimadamore@1434 218 };
mcimadamore@1434 219
vromero@1482 220 FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind,
vromero@1482 221 SamKind samKind, MethodKind samMeth, MethodKind clientMeth,
vromero@1482 222 TypeKind retType, TypeKind argType, TypeKind thrownType,
vromero@1482 223 ExprKind exprKind) {
mcimadamore@1434 224 this.samPkg = samPkg;
mcimadamore@1434 225 this.modKind = modKind;
mcimadamore@1434 226 this.samKind = samKind;
mcimadamore@1434 227 this.samMeth = samMeth;
mcimadamore@1434 228 this.clientMeth = clientMeth;
mcimadamore@1434 229 this.retType = retType;
mcimadamore@1434 230 this.argType = argType;
mcimadamore@1434 231 this.thrownType = thrownType;
mcimadamore@1434 232 this.exprKind = exprKind;
mcimadamore@1434 233 this.dc = new DiagnosticChecker();
mcimadamore@1434 234 }
mcimadamore@1434 235
vromero@1482 236 @Override
vromero@1482 237 public void run() {
vromero@1482 238 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
vromero@1482 239
vromero@1482 240 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, null, null,
vromero@1482 241 Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
vromero@1482 242 try {
vromero@1482 243 ct.analyze();
vromero@1482 244 } catch (IOException ex) {
vromero@1482 245 throw new AssertionError("Test failing with cause", ex.getCause());
vromero@1482 246 }
mcimadamore@1434 247 if (dc.errorFound == checkSamConversion()) {
vromero@1482 248 throw new AssertionError(samSourceFile + "\n\n" +
vromero@1482 249 pkgClassSourceFile + "\n\n" + clientSourceFile);
mcimadamore@1434 250 }
mcimadamore@1434 251 }
mcimadamore@1434 252
mcimadamore@1434 253 boolean checkSamConversion() {
mcimadamore@1434 254 if (samKind != SamKind.INTERFACE) {
mcimadamore@1434 255 //sam type must be an interface
mcimadamore@1434 256 return false;
mcimadamore@1434 257 } else if (samMeth == MethodKind.NONE) {
mcimadamore@1434 258 //interface must have at least a method
mcimadamore@1434 259 return false;
mcimadamore@1434 260 } else if (exprKind == ExprKind.LAMBDA &&
mcimadamore@1434 261 samMeth != MethodKind.NON_GENERIC) {
mcimadamore@1434 262 //target method for lambda must be non-generic
mcimadamore@1434 263 return false;
mcimadamore@1434 264 } else if (exprKind == ExprKind.MREF &&
mcimadamore@1434 265 clientMeth == MethodKind.NONE) {
mcimadamore@1434 266 return false;
mcimadamore@1434 267 } else if (samPkg != PackageKind.NO_PKG &&
mcimadamore@1434 268 modKind != ModifierKind.PUBLIC &&
mcimadamore@1434 269 (retType == TypeKind.PKG_CLASS ||
mcimadamore@1434 270 argType == TypeKind.PKG_CLASS ||
mcimadamore@1434 271 thrownType == TypeKind.PKG_CLASS)) {
mcimadamore@1434 272 //target must not contain inaccessible types
mcimadamore@1434 273 return false;
mcimadamore@1434 274 } else {
mcimadamore@1434 275 return true;
mcimadamore@1434 276 }
mcimadamore@1434 277 }
mcimadamore@1434 278
mcimadamore@1434 279 abstract class SourceFile extends SimpleJavaFileObject {
mcimadamore@1434 280
mcimadamore@1434 281 protected String template;
mcimadamore@1434 282
mcimadamore@1434 283 public SourceFile(String filename, String template) {
mcimadamore@1434 284 super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
mcimadamore@1434 285 this.template = template;
mcimadamore@1434 286 }
mcimadamore@1434 287
mcimadamore@1434 288 @Override
mcimadamore@1434 289 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
mcimadamore@1434 290 return toString();
mcimadamore@1434 291 }
mcimadamore@1434 292
vromero@1482 293 @Override
mcimadamore@1434 294 public abstract String toString();
mcimadamore@1434 295 }
mcimadamore@1434 296
vromero@1482 297 static class DiagnosticChecker
vromero@1482 298 implements javax.tools.DiagnosticListener<JavaFileObject> {
mcimadamore@1434 299
mcimadamore@1434 300 boolean errorFound = false;
mcimadamore@1434 301
vromero@1482 302 @Override
mcimadamore@1434 303 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
mcimadamore@1434 304 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
mcimadamore@1434 305 errorFound = true;
mcimadamore@1434 306 }
mcimadamore@1434 307 }
mcimadamore@1434 308 }
mcimadamore@1434 309 }

mercurial