1 /* 2 * Copyright (c) 2012, 2018, 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 8003280 8006694 8129962 27 * @summary Add lambda tests 28 * Automatic test for checking correctness of structural most specific test routine 29 * temporarily workaround combo tests are causing time out in several platforms 30 * @enablePreview 31 * @library /tools/javac/lib 32 * @modules jdk.compiler/com.sun.tools.javac.api 33 * jdk.compiler/com.sun.tools.javac.file 34 * jdk.compiler/com.sun.tools.javac.util 35 * @build combo.ComboTestHelper 36 37 * @run main StructuralMostSpecificTest 38 */ 39 40 import javax.lang.model.element.Element; 41 import javax.tools.Diagnostic; 42 import javax.tools.JavaFileObject; 43 import com.sun.tools.javac.api.ClientCodeWrapper; 44 import com.sun.tools.javac.util.JCDiagnostic; 45 import com.sun.tools.javac.util.List; 46 import combo.ComboInstance; 47 import combo.ComboParameter; 48 import combo.ComboTask.Result; 49 import combo.ComboTestHelper; 50 51 public class StructuralMostSpecificTest extends ComboInstance<StructuralMostSpecificTest> { 52 53 enum RetTypeKind implements ComboParameter { 54 SHORT("short"), 55 INT("int"), 56 OBJECT("Object"), 57 INTEGER("Integer"), 58 VOID("void"), 59 J_L_VOID("Void"); 60 61 String retTypeStr; 62 63 RetTypeKind(String retTypeStr) { 64 this.retTypeStr = retTypeStr; 65 } 66 67 boolean moreSpecificThan(RetTypeKind rk) { 68 return moreSpecificThan[this.ordinal()][rk.ordinal()]; 69 } 70 71 static boolean[][] moreSpecificThan = { 72 // SHORT | INT | OBJECT | INTEGER | VOID | J_L_VOID 73 /* SHORT */ { true , true , true , false , false , false }, 74 /* INT */ { false , true , true , true , false , false }, 75 /* OBJECT */ { false , false , true , false , false , false }, 76 /* INTEGER */ { false , false , true , true , false , false }, 77 /* VOID */ { false , false , false , false , true , true }, 78 /* J_L_VOID */{ false , false , true , false , false , true } }; 79 80 public String expand(String optParameter) { 81 return retTypeStr; 82 } 83 } 84 85 enum ArgTypeKind implements ComboParameter { 86 SHORT("short"), 87 INT("int"), 88 BOOLEAN("boolean"), 89 OBJECT("Object"), 90 INTEGER("Integer"), 91 DOUBLE("Double"); 92 93 String argTypeStr; 94 95 ArgTypeKind(String typeStr) { 96 this.argTypeStr = typeStr; 97 } 98 99 public String expand(String optParameter) { 100 return argTypeStr; 101 } 102 } 103 104 enum ExceptionKind implements ComboParameter { 105 NONE(""), 106 EXCEPTION("throws Exception"), 107 SQL_EXCEPTION("throws java.sql.SQLException"), 108 IO_EXCEPTION("throws java.io.IOException"); 109 110 String exceptionStr; 111 112 ExceptionKind(String exceptionStr) { 113 this.exceptionStr = exceptionStr; 114 } 115 116 public String expand(String optParameter) { 117 return exceptionStr; 118 } 119 } 120 121 enum LambdaReturnKind implements ComboParameter { 122 VOID("return;"), 123 SHORT("return (short)0;"), 124 INT("return 0;"), 125 INTEGER("return (Integer)null;"), 126 NULL("return null;"); 127 128 String retStr; 129 130 LambdaReturnKind(String retStr) { 131 this.retStr = retStr; 132 } 133 134 boolean compatibleWith(RetTypeKind rk) { 135 return compatibleWith[rk.ordinal()][ordinal()]; 136 } 137 138 static boolean[][] compatibleWith = { 139 // VOID | SHORT | INT | INTEGER | NULL 140 /* SHORT */ { false , true , false , false , false }, 141 /* INT */ { false , true , true , true , false }, 142 /* OBJECT */ { false , true , true , true , true }, 143 /* INTEGER */ { false , false , true , true , true }, 144 /* VOID */ { true , false , false , false , false }, 145 /* J_L_VOID */{ false , false , false , false , true } }; 146 147 boolean needsConversion(RetTypeKind rk) { 148 return needsConversion[rk.ordinal()][ordinal()]; 149 } 150 151 static boolean[][] needsConversion = { 152 // VOID | SHORT | INT | INTEGER | NULL 153 /* SHORT */ { false , false , false , false , false }, 154 /* INT */ { false , false , false , true , false }, 155 /* OBJECT */ { false , true , true , false , false }, 156 /* INTEGER */ { false , false , true , false , false }, 157 /* VOID */ { false , false , false , false , false }, 158 /* J_L_VOID */{ true , false , false , false , false } }; 159 160 public String expand(String optParameter) { 161 return retStr; 162 } 163 } 164 165 static final String sourceTemplate = 166 "interface SAM1 {\n" + 167 " #{RET[0]} m(#{ARG[0]} a1) #{EX[0]};\n" + 168 "}\n" + 169 "interface SAM2 {\n" + 170 " #{RET[1]} m(#{ARG[1]} a1) #{EX[1]};\n" + 171 "}\n" + 172 "class Test {\n" + 173 " void m(SAM1 s) { }\n" + 174 " void m(SAM2 s) { }\n" + 175 " { m((#{ARG[0]} x)->{ #{EXPR} }); }\n" + 176 "}\n"; 177 178 public static void main(String... args) throws Exception { 179 new ComboTestHelper<StructuralMostSpecificTest>() 180 .withFilter(StructuralMostSpecificTest::hasSameArguments) 181 .withFilter(StructuralMostSpecificTest::hasCompatibleReturns) 182 .withFilter(StructuralMostSpecificTest::hasSameOverloadPhase) 183 .withDimension("EXPR", (x, expr) -> x.lambdaReturnKind = expr, LambdaReturnKind.values()) 184 .withArrayDimension("RET", (x, ret, idx) -> x.returnType[idx] = ret, 2, RetTypeKind.values()) 185 .withArrayDimension("EX", 2, ExceptionKind.values()) 186 .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKind[idx] = arg, 2, ArgTypeKind.values()) 187 .run(StructuralMostSpecificTest::new); 188 } 189 190 LambdaReturnKind lambdaReturnKind; 191 RetTypeKind[] returnType = new RetTypeKind[2]; 192 ArgTypeKind[] argumentKind = new ArgTypeKind[2]; 193 194 boolean hasSameArguments() { 195 return argumentKind[0] == argumentKind[1]; 196 } 197 198 boolean hasCompatibleReturns() { 199 return lambdaReturnKind.compatibleWith(returnType[0]) && 200 lambdaReturnKind.compatibleWith(returnType[1]); 201 } 202 203 boolean hasSameOverloadPhase() { 204 return lambdaReturnKind.needsConversion(returnType[0]) == lambdaReturnKind.needsConversion(returnType[1]); 205 } 206 207 @Override 208 public void doWork() throws Throwable { 209 newCompilationTask() 210 .withSourceFromTemplate(sourceTemplate) 211 .withOption("--debug=verboseResolution=all,-predef,-internal,-object-init") 212 .analyze(this::check); 213 } 214 215 void check(Result<Iterable<? extends Element>> result) { 216 boolean m1MoreSpecific = returnType[0].moreSpecificThan(returnType[1]); 217 boolean m2MoreSpecific = returnType[1].moreSpecificThan(returnType[0]); 218 219 boolean ambiguous = (m1MoreSpecific == m2MoreSpecific); 220 221 if (ambiguous != ambiguityFound(result)) { 222 fail("invalid diagnostics for combo:\n" + 223 result.compilationInfo() + "\n" + 224 "\nAmbiguity found: " + ambiguityFound(result) + 225 "\nm1 more specific: " + m1MoreSpecific + 226 "\nm2 more specific: " + m2MoreSpecific + 227 "\nexpected ambiguity: " + ambiguous); 228 } 229 230 if (!ambiguous) { 231 String sigToCheck = m1MoreSpecific ? "m(SAM1)" : "m(SAM2)"; 232 if (!sigToCheck.equals(mostSpecificSignature(result))) { 233 fail("invalid most specific method selected:\n" + 234 result.compilationInfo() + "\n" + 235 "\nMost specific found: " + mostSpecificSignature(result) + 236 "\nm1 more specific: " + m1MoreSpecific + 237 "\nm2 more specific: " + m2MoreSpecific); 238 } 239 } 240 } 241 242 boolean ambiguityFound(Result<Iterable<? extends Element>> result) { 243 return result.containsKey("compiler.err.ref.ambiguous"); 244 } 245 246 String mostSpecificSignature(Result<Iterable<? extends Element>> result) { 247 List<Diagnostic<? extends JavaFileObject>> rsDiag = 248 result.diagnosticsForKey("compiler.note.verbose.resolve.multi"); 249 if (rsDiag.nonEmpty()) { 250 ClientCodeWrapper.DiagnosticSourceUnwrapper dsu = 251 (ClientCodeWrapper.DiagnosticSourceUnwrapper)rsDiag.head; 252 JCDiagnostic.MultilineDiagnostic mdiag = 253 (JCDiagnostic.MultilineDiagnostic)dsu.d; 254 int mostSpecificIndex = (Integer)mdiag.getArgs()[2]; 255 return mdiag.getSubdiagnostics().get(mostSpecificIndex).getArgs()[1].toString(); 256 } else { 257 return null; 258 } 259 } 260 }