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