TypeInferenceComboTest.java revision 1519:5c956be64b9e
1264391Snwhitehorn/*
2264391Snwhitehorn * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
3264391Snwhitehorn * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4264391Snwhitehorn *
5264391Snwhitehorn * This code is free software; you can redistribute it and/or modify it
6264404Snwhitehorn * under the terms of the GNU General Public License version 2 only, as
7264404Snwhitehorn * published by the Free Software Foundation.
8294060Ssmh *
9294060Ssmh * This code is distributed in the hope that it will be useful, but WITHOUT
10264391Snwhitehorn * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11264391Snwhitehorn * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12264391Snwhitehorn * version 2 for more details (a copy is included in the LICENSE file that
13264391Snwhitehorn * accompanied this code).
14264391Snwhitehorn *
15264391Snwhitehorn * You should have received a copy of the GNU General Public License version
16264391Snwhitehorn * 2 along with this work; if not, write to the Free Software Foundation,
17264391Snwhitehorn * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18264391Snwhitehorn *
19264391Snwhitehorn * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20264391Snwhitehorn * or visit www.oracle.com if you need additional information or have any
21264391Snwhitehorn * questions.
22264391Snwhitehorn */
23264391Snwhitehorn
24264391Snwhitehorn/**
25264391Snwhitehorn * @test
26264391Snwhitehorn * @bug 8003280 8006694
27264391Snwhitehorn * @summary Add lambda tests
28293460Ssmh *  perform automated checks in type inference in lambda expressions
29264391Snwhitehorn *  in different contexts
30264391Snwhitehorn *  temporarily workaround combo tests are causing time out in several platforms
31271762Semaste * @library ../../../lib
32264391Snwhitehorn * @build JavacTestingAbstractThreadedTest
33294060Ssmh * @compile  TypeInferenceComboTest.java
34294765Simp * @run main/othervm/timeout=360 TypeInferenceComboTest
35294060Ssmh */
36294060Ssmh
37294060Ssmh// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
38294068Ssmh// see JDK-8006746
39294068Ssmh
40294068Ssmhimport java.net.URI;
41294060Ssmhimport java.util.Arrays;
42294060Ssmhimport javax.tools.Diagnostic;
43294060Ssmhimport javax.tools.JavaFileObject;
44294060Ssmhimport javax.tools.SimpleJavaFileObject;
45264391Snwhitehornimport com.sun.source.util.JavacTask;
46294060Ssmh
47294060Ssmhpublic class TypeInferenceComboTest
48294060Ssmh    extends JavacTestingAbstractThreadedTest
49294060Ssmh    implements Runnable {
50293460Ssmh    enum Context {
51293724Ssmh        ASSIGNMENT("SAM#Type s = #LBody;"),
52264391Snwhitehorn        METHOD_CALL("#GenericDeclKind void method1(SAM#Type s) { }\n" +
53294060Ssmh                    "void method2() {\n" +
54294060Ssmh                    "    method1(#LBody);\n" +
55264391Snwhitehorn                    "}"),
56294060Ssmh        RETURN_OF_METHOD("SAM#Type method1() {\n" +
57294060Ssmh                "    return #LBody;\n" +
58281169Sandrew                "}"),
59264391Snwhitehorn        LAMBDA_RETURN_EXPRESSION("SAM2 s2 = () -> {return (SAM#Type)#LBody;};\n"),
60264391Snwhitehorn        ARRAY_INITIALIZER("Object[] oarray = {\"a\", 1, (SAM#Type)#LBody};");
61264391Snwhitehorn
62264391Snwhitehorn        String context;
63271762Semaste
64264391Snwhitehorn        Context(String context) {
65294060Ssmh            this.context = context;
66294060Ssmh        }
67294060Ssmh
68294060Ssmh        String getContext(SamKind sk, TypeKind samTargetT, Keyword kw,
69294060Ssmh                TypeKind parameterT, TypeKind returnT, LambdaKind lk,
70294060Ssmh                ParameterKind pk, GenericDeclKind gdk, LambdaBody lb) {
71294060Ssmh            String result = context;
72294060Ssmh            if (sk == SamKind.GENERIC) {
73294060Ssmh                if(this == Context.METHOD_CALL) {
74264391Snwhitehorn                    result = result.replaceAll("#GenericDeclKind",
75294060Ssmh                            gdk.getGenericDeclKind(samTargetT));
76294060Ssmh                    if(gdk == GenericDeclKind.NON_GENERIC)
77294060Ssmh                        result = result.replaceAll("#Type", "<" +
78294060Ssmh                                samTargetT.typeStr + ">");
79294060Ssmh                    else //#GenericDeclKind is <T> or <T extends xxx>
80294060Ssmh                        result = result.replaceAll("#Type", "<T>");
81294060Ssmh                }
82294060Ssmh                else {
83264391Snwhitehorn                    if(kw == Keyword.VOID)
84294060Ssmh                        result = result.replaceAll("#Type", "<" +
85294060Ssmh                                samTargetT.typeStr + ">");
86294060Ssmh                    else
87294060Ssmh                        result = result.replaceAll("#Type", "<? " + kw.keyStr +
88294060Ssmh                                " " + samTargetT.typeStr + ">");
89294060Ssmh                }
90294060Ssmh            }
91294060Ssmh            else
92294060Ssmh                result = result.replaceAll("#Type", "").
93294060Ssmh                        replaceAll("#GenericDeclKind", "");
94294768Simp
95294060Ssmh            return result.replaceAll("#LBody",
96294768Simp                    lb.getLambdaBody(samTargetT, parameterT, returnT, lk, pk));
97294060Ssmh        }
98294060Ssmh    }
99294060Ssmh
100264391Snwhitehorn    enum SamKind {
101294060Ssmh        GENERIC("interface SAM<T> { #R m(#ARG); }"),
102294768Simp        NON_GENERIC("interface SAM { #R m(#ARG); }");
103294768Simp
104294768Simp        String sam_str;
105294768Simp
106294768Simp        SamKind(String sam_str) {
107294768Simp            this.sam_str = sam_str;
108294768Simp        }
109294768Simp
110294768Simp        String getSam(TypeKind parameterT, TypeKind returnT) {
111294768Simp            return sam_str.replaceAll("#ARG",
112294768Simp                    parameterT == TypeKind.VOID ?
113294768Simp                        "" : parameterT.typeStr + " arg")
114294768Simp                    .replaceAll("#R", returnT.typeStr);
115294768Simp        }
116294768Simp    }
117294768Simp
118294768Simp    enum TypeKind {
119294768Simp        VOID("void", ""),
120294768Simp        STRING("String", "\"hello\""),
121294768Simp        INTEGER("Integer", "1"),
122294768Simp        INT("int", "0"),
123294768Simp        COMPARATOR("java.util.Comparator<String>",
124294768Simp                "(java.util.Comparator<String>)(a, b) -> a.length()-b.length()"),
125294768Simp        SAM("SAM2", "null"),
126294768Simp        GENERIC("T", null);
127294768Simp
128294768Simp        String typeStr;
129294765Simp        String valStr;
130294060Ssmh
131294060Ssmh        TypeKind(String typeStr, String valStr) {
132294060Ssmh            this.typeStr = typeStr;
133294060Ssmh            this.valStr = valStr;
134294765Simp        }
135294765Simp    }
136294060Ssmh
137294060Ssmh    enum LambdaKind {
138294060Ssmh        EXPRESSION("#VAL"),
139294060Ssmh        STATEMENT("{return #VAL;}");
140294060Ssmh
141294060Ssmh        String stmt;
142294060Ssmh
143294060Ssmh        LambdaKind(String stmt) {
144294060Ssmh            this.stmt = stmt;
145294060Ssmh        }
146294768Simp    }
147294768Simp
148294768Simp    enum ParameterKind {
149294060Ssmh        EXPLICIT("#TYPE"),
150294060Ssmh        IMPLICIT("");
151294060Ssmh
152294060Ssmh        String paramTemplate;
153294060Ssmh
154294060Ssmh        ParameterKind(String paramTemplate) {
155294060Ssmh             this.paramTemplate = paramTemplate;
156294060Ssmh        }
157294768Simp    }
158294768Simp
159294060Ssmh    enum Keyword {
160294060Ssmh        SUPER("super"),
161294060Ssmh        EXTENDS("extends"),
162294284Semaste        VOID("");
163294284Semaste
164294768Simp        String keyStr;
165294768Simp
166294768Simp        Keyword(String keyStr) {
167294060Ssmh            this.keyStr = keyStr;
168294060Ssmh        }
169294060Ssmh    }
170294060Ssmh
171294060Ssmh    enum LambdaBody {
172294060Ssmh        //no parameters, return type is one of the TypeKind
173294060Ssmh        RETURN_VOID("() -> #RET"),
174294060Ssmh        //has parameters, return type is one of the TypeKind
175294060Ssmh        RETURN_ARG("(#PK arg) -> #RET");
176271762Semaste
177281059Srpaulo        String bodyStr;
178294060Ssmh
179264391Snwhitehorn        LambdaBody(String bodyStr) {
180294060Ssmh            this.bodyStr = bodyStr;
181264391Snwhitehorn        }
182264391Snwhitehorn
183294060Ssmh        String getLambdaBody(TypeKind samTargetT, TypeKind parameterT,
184264391Snwhitehorn                TypeKind returnT, LambdaKind lk, ParameterKind pk) {
185294060Ssmh            String result = bodyStr.replaceAll("#PK", pk.paramTemplate);
186294060Ssmh
187271762Semaste            if(result.contains("#TYPE")) {
188271762Semaste                if (parameterT == TypeKind.GENERIC && this != RETURN_VOID)
189271762Semaste                    result = result.replaceAll("#TYPE",
190271762Semaste                            samTargetT == null? "": samTargetT.typeStr);
191281059Srpaulo                else
192281059Srpaulo                    result = result.replaceAll("#TYPE", parameterT.typeStr);
193281059Srpaulo            }
194281059Srpaulo            if (this == RETURN_ARG && parameterT == returnT)
195281059Srpaulo                return result.replaceAll("#RET", lk.stmt.replaceAll("#VAL", "arg"));
196281059Srpaulo            else {
197281059Srpaulo                if(returnT != TypeKind.GENERIC)
198293274Ssmh                    return result.replaceAll("#RET", lk.stmt.replaceAll("#VAL",
199281059Srpaulo                            (returnT==TypeKind.VOID &&
200281059Srpaulo                            lk==LambdaKind.EXPRESSION) ? "{}" : returnT.valStr));
201281059Srpaulo                else
202281059Srpaulo                    return result.replaceAll("#RET",
203281059Srpaulo                            lk.stmt.replaceAll("#VAL", samTargetT.valStr));
204281059Srpaulo            }
205281059Srpaulo        }
206281059Srpaulo    }
207281059Srpaulo
208281059Srpaulo    enum GenericDeclKind {
209281059Srpaulo        NON_GENERIC(""),
210271762Semaste        GENERIC_NOBOUND("<T>"),
211294060Ssmh        GENERIC_BOUND("<T extends #ExtendedType>");
212294765Simp        String typeStr;
213294060Ssmh
214294060Ssmh        GenericDeclKind(String typeStr) {
215294060Ssmh            this.typeStr = typeStr;
216264391Snwhitehorn        }
217264391Snwhitehorn
218294060Ssmh        String getGenericDeclKind(TypeKind et) {
219294060Ssmh            return typeStr.replaceAll("#ExtendedType", et==null? "":et.typeStr);
220294060Ssmh        }
221294060Ssmh    }
222294060Ssmh
223264391Snwhitehorn    boolean checkTypeInference() {
224294060Ssmh        if (parameterType == TypeKind.VOID) {
225294060Ssmh            if (lambdaBodyType != LambdaBody.RETURN_VOID)
226294060Ssmh                return false;
227294060Ssmh        }
228294060Ssmh        else if (lambdaBodyType != LambdaBody.RETURN_ARG)
229294060Ssmh            return false;
230264391Snwhitehorn        if (  genericDeclKind == GenericDeclKind.GENERIC_NOBOUND ||
231294060Ssmh                genericDeclKind == GenericDeclKind.GENERIC_BOUND ) {
232294060Ssmh            if ( parameterType == TypeKind.GENERIC &&
233294060Ssmh                    parameterKind == ParameterKind.IMPLICIT) //cyclic inference
234294060Ssmh                return false;
235294060Ssmh        }
236294060Ssmh        return true;
237294060Ssmh    }
238294060Ssmh
239294060Ssmh    String templateStr = "#C\n" +
240294060Ssmh                         "interface SAM2 {\n" +
241294060Ssmh                         "    SAM m();\n" +
242294060Ssmh                         "}\n";
243294060Ssmh    SourceFile samSourceFile = new SourceFile("Sam.java", templateStr) {
244294060Ssmh        public String toString() {
245294060Ssmh            return template.replaceAll("#C",
246294060Ssmh                    samKind.getSam(parameterType, returnType));
247294060Ssmh        }
248294060Ssmh    };
249294060Ssmh
250294060Ssmh    SourceFile clientSourceFile = new SourceFile("Client.java",
251294060Ssmh                                                 "class Client { \n" +
252294060Ssmh                                                 "    #Context\n" +
253264391Snwhitehorn                                                 "}") {
254294060Ssmh        public String toString() {
255294060Ssmh            return template.replaceAll("#Context",
256294060Ssmh                    context.getContext(samKind, samTargetType, keyword,
257294060Ssmh                    parameterType, returnType, lambdaKind, parameterKind,
258294060Ssmh                    genericDeclKind, lambdaBodyType));
259294060Ssmh        }
260294060Ssmh    };
261294060Ssmh
262264391Snwhitehorn    public void run() {
263294060Ssmh        DiagnosticChecker dc = new DiagnosticChecker();
264294060Ssmh        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), dc,
265294060Ssmh                null, null, Arrays.asList(samSourceFile, clientSourceFile));
266294060Ssmh        try {
267294060Ssmh            ct.analyze();
268294060Ssmh        } catch (Throwable t) {
269294060Ssmh            processException(t);
270264391Snwhitehorn        }
271294060Ssmh        if (dc.errorFound == checkTypeInference()) {
272264391Snwhitehorn            throw new AssertionError(samSourceFile + "\n\n" +
273294060Ssmh                    clientSourceFile + "\n" + parameterType + " " + returnType);
274294060Ssmh        }
275294060Ssmh    }
276294060Ssmh
277294060Ssmh    abstract class SourceFile extends SimpleJavaFileObject {
278294060Ssmh
279294060Ssmh        protected String template;
280264391Snwhitehorn
281294060Ssmh        public SourceFile(String filename, String template) {
282294060Ssmh            super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
283294060Ssmh            this.template = template;
284294060Ssmh        }
285281058Srpaulo
286294060Ssmh        @Override
287294060Ssmh        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
288264391Snwhitehorn            return toString();
289264391Snwhitehorn        }
290294060Ssmh
291294060Ssmh        public abstract String toString();
292264391Snwhitehorn    }
293294060Ssmh
294294060Ssmh    static class DiagnosticChecker
295294060Ssmh        implements javax.tools.DiagnosticListener<JavaFileObject> {
296264391Snwhitehorn
297294060Ssmh        boolean errorFound = false;
298264391Snwhitehorn
299294060Ssmh        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
300294060Ssmh            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
301294060Ssmh                errorFound = true;
302294060Ssmh            }
303264391Snwhitehorn        }
304294060Ssmh    }
305294060Ssmh
306294060Ssmh    SamKind samKind;
307294060Ssmh    TypeKind samTargetType;
308294060Ssmh    TypeKind parameterType;
309264391Snwhitehorn    TypeKind returnType;
310294060Ssmh    Context context;
311294060Ssmh    LambdaBody lambdaBodyType;
312264391Snwhitehorn    LambdaKind lambdaKind;
313294060Ssmh    ParameterKind parameterKind;
314294060Ssmh    Keyword keyword;
315294060Ssmh    GenericDeclKind genericDeclKind;
316264391Snwhitehorn
317294060Ssmh    TypeInferenceComboTest(SamKind sk, TypeKind samTargetT, TypeKind parameterT,
318294060Ssmh            TypeKind returnT, LambdaBody lb, Context c, LambdaKind lk,
319294060Ssmh            ParameterKind pk, Keyword kw, GenericDeclKind gdk) {
320294060Ssmh        samKind = sk;
321264414Snwhitehorn        samTargetType = samTargetT;
322264414Snwhitehorn        parameterType = parameterT;
323294060Ssmh        returnType = returnT;
324294060Ssmh        context = c;
325281058Srpaulo        lambdaKind = lk;
326294060Ssmh        parameterKind = pk;
327294060Ssmh        keyword = kw;
328294060Ssmh        lambdaBodyType = lb;
329294060Ssmh        genericDeclKind = gdk;
330264391Snwhitehorn    }
331294060Ssmh
332294060Ssmh    public static void main(String[] args) throws Exception {
333294060Ssmh        for(Context ct : Context.values()) {
334294060Ssmh            for (TypeKind returnT : TypeKind.values()) {
335294060Ssmh                for (TypeKind parameterT : TypeKind.values()) {
336294060Ssmh                    for(LambdaBody lb : LambdaBody.values()) {
337294060Ssmh                        for (ParameterKind parameterK : ParameterKind.values()) {
338294060Ssmh                            for(LambdaKind lambdaK : LambdaKind.values()) {
339294060Ssmh                                for (SamKind sk : SamKind.values()) {
340294060Ssmh                                    if (sk == SamKind.NON_GENERIC) {
341294060Ssmh                                        generateNonGenericSAM(ct, returnT,
342294060Ssmh                                                parameterT, lb, parameterK,
343294060Ssmh                                                lambdaK, sk);
344294060Ssmh                                    }
345294060Ssmh                                    else if (sk == SamKind.GENERIC) {
346294060Ssmh                                        generateGenericSAM(ct, returnT,
347294060Ssmh                                                parameterT, lb, parameterK,
348281058Srpaulo                                                lambdaK, sk);
349294060Ssmh                                    }
350294060Ssmh                                }
351264391Snwhitehorn                            }
352264391Snwhitehorn                        }
353294060Ssmh                    }
354294060Ssmh                }
355264391Snwhitehorn            }
356294060Ssmh        }
357264391Snwhitehorn
358294060Ssmh        checkAfterExec(false);
359294060Ssmh    }
360264391Snwhitehorn
361264391Snwhitehorn    static void generateNonGenericSAM(Context ct, TypeKind returnT,
362264391Snwhitehorn            TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
363294060Ssmh            LambdaKind lambdaK, SamKind sk) {
364294060Ssmh        if(parameterT != TypeKind.GENERIC && returnT != TypeKind.GENERIC ) {
365281058Srpaulo            pool.execute(new TypeInferenceComboTest(sk, null, parameterT,
366294060Ssmh                    returnT, lb, ct, lambdaK, parameterK, null, null));
367264391Snwhitehorn        }
368264391Snwhitehorn    }
369293460Ssmh
370264391Snwhitehorn    static void generateGenericSAM(Context ct, TypeKind returnT,
371264391Snwhitehorn            TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
372264391Snwhitehorn            LambdaKind lambdaK, SamKind sk) {
373264391Snwhitehorn        for (Keyword kw : Keyword.values()) {
374293460Ssmh            for (TypeKind samTargetT : TypeKind.values()) {
375264391Snwhitehorn                if(samTargetT != TypeKind.VOID &&
376293460Ssmh                   samTargetT != TypeKind.INT &&
377264391Snwhitehorn                   samTargetT != TypeKind.GENERIC &&
378293460Ssmh                   (parameterT == TypeKind.GENERIC ||
379264391Snwhitehorn                   returnT == TypeKind.GENERIC)) {
380264391Snwhitehorn                    if(ct != Context.METHOD_CALL) {
381264391Snwhitehorn                        pool.execute(
382264391Snwhitehorn                            new TypeInferenceComboTest(sk, samTargetT, parameterT,
383293460Ssmh                                returnT, lb, ct, lambdaK, parameterK, kw, null));
384293460Ssmh                    } else {//Context.METHOD_CALL
385264391Snwhitehorn                        for (GenericDeclKind gdk :
386264391Snwhitehorn                                GenericDeclKind.values())
387264391Snwhitehorn                            pool.execute(
388264391Snwhitehorn                                    new TypeInferenceComboTest(sk, samTargetT,
389264391Snwhitehorn                                    parameterT, returnT, lb, ct, lambdaK,
390264391Snwhitehorn                                    parameterK, kw, gdk));
391264391Snwhitehorn                    }
392264391Snwhitehorn                }
393264391Snwhitehorn            }
394264391Snwhitehorn         }
395264391Snwhitehorn    }
396264391Snwhitehorn
397}
398