OpenJDK / jdk / hs
changeset 48091:469e42d314a4
8178427: NPE in Infer$CheckUpperBounds
Summary: void target-type causes a crash during overload resolution
Reviewed-by: vromero
author | mcimadamore |
---|---|
date | Tue, 28 Nov 2017 18:51:55 +0000 |
parents | a1f88c937a77 |
children | 78a309f079af |
files | src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java test/langtools/tools/javac/generics/inference/8178427/T8178427.java |
diffstat | 2 files changed, 95 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java Tue Nov 28 10:15:47 2017 -0800 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java Tue Nov 28 18:51:55 2017 +0000 @@ -57,6 +57,7 @@ import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.DiagnosticSource; +import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; @@ -98,6 +99,7 @@ protected static final Context.Key<ArgumentAttr> methodAttrKey = new Context.Key<>(); private final DeferredAttr deferredAttr; + private final JCDiagnostic.Factory diags; private final Attr attr; private final Symtab syms; private final Log log; @@ -121,6 +123,7 @@ protected ArgumentAttr(Context context) { context.put(methodAttrKey, this); deferredAttr = DeferredAttr.instance(context); + diags = JCDiagnostic.Factory.instance(context); attr = Attr.instance(context); syms = Symtab.instance(context); log = Log.instance(context); @@ -482,18 +485,14 @@ List<JCReturn> returnExpressions() { return returnExpressions.orElseGet(() -> { final List<JCReturn> res; - if (speculativeTree.getBodyKind() == BodyKind.EXPRESSION) { - res = List.of(attr.make.Return((JCExpression)speculativeTree.body)); - } else { - ListBuffer<JCReturn> returnExpressions = new ListBuffer<>(); - new LambdaReturnScanner() { - @Override - public void visitReturn(JCReturn tree) { - returnExpressions.add(tree); - } - }.scan(speculativeTree.body); - res = returnExpressions.toList(); - } + ListBuffer<JCReturn> buf = new ListBuffer<>(); + new LambdaReturnScanner() { + @Override + public void visitReturn(JCReturn tree) { + buf.add(tree); + } + }.scan(speculativeTree.body); + res = buf.toList(); returnExpressions = Optional.of(res); return res; }); @@ -519,16 +518,38 @@ private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) { CheckContext checkContext = resultInfo.checkContext; ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo); - for (JCReturn ret : returnExpressions()) { - Type t = getReturnType(ret); - if (speculativeTree.getBodyKind() == BodyKind.EXPRESSION || !t.hasTag(VOID)) { - checkSpeculative(ret.expr, t, bodyResultInfo); - } + switch (speculativeTree.getBodyKind()) { + case EXPRESSION: + checkSpeculative(speculativeTree.body, speculativeTree.body.type, bodyResultInfo); + break; + case STATEMENT: + for (JCReturn ret : returnExpressions()) { + checkReturnInStatementLambda(ret, bodyResultInfo); + } + break; } attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext); } + /** + * This is an inlined version of {@link Attr#visitReturn(JCReturn)}. + */ + void checkReturnInStatementLambda(JCReturn ret, ResultInfo resultInfo) { + if (resultInfo.pt.hasTag(VOID) && ret.expr != null) { + //fail - if the function type's result is void, the lambda body must be a void-compatible block. + resultInfo.checkContext.report(speculativeTree.pos(), + diags.fragment("unexpected.ret.val")); + } else if (!resultInfo.pt.hasTag(VOID)) { + if (ret.expr == null) { + //fail - if the function type's result is non-void, the lambda body must be a value-compatible block. + resultInfo.checkContext.report(speculativeTree.pos(), + diags.fragment("missing.ret.val")); + } + checkSpeculative(ret.expr, ret.expr.type, resultInfo); + } + } + /** Get the type associated with given return expression. */ Type getReturnType(JCReturn ret) { if (ret.expr == null) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/generics/inference/8178427/T8178427.java Tue Nov 28 18:51:55 2017 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8178427 + * @summary NPE in Infer$CheckUpperBounds + * @compile T8178427.java + */ + +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.function.*; +import java.util.stream.*; + +abstract class X { + public interface N<K, V> { + Stream<V> getValues(); + } + + abstract <K, V> N<K, V> c(); + + abstract <T, K, V, M extends N<K, V>> Collector<T, ?, M> f( + Function<? super T, ? extends K> k, + Function<? super T, ? extends Stream<? extends V>> v, + Supplier<M> multimapSupplier); + + void m(Map<String, N<?, ?>> c, ExecutorService s) { + s.submit(() -> { + return c.entrySet().parallelStream() + .collect(f(Map.Entry::getKey, e -> e.getValue().getValues(), this::c)); + }); + } +} +