langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
changeset 45756 67f4f8f4d34a
parent 45750 15404afd36ab
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Jun 29 14:32:39 2017 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 30 05:47:35 2017 -0700
@@ -2515,14 +2515,9 @@
                 //add thrown types as bounds to the thrown types free variables if needed:
                 if (resultInfo.checkContext.inferenceContext().free(lambdaType.getThrownTypes())) {
                     List<Type> inferredThrownTypes = flow.analyzeLambdaThrownTypes(env, that, make);
-                    List<Type> thrownTypes = resultInfo.checkContext.inferenceContext().asUndetVars(lambdaType.getThrownTypes());
-
-                    chk.unhandled(inferredThrownTypes, thrownTypes);
-
-                    //18.2.5: "In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej"
-                    thrownTypes.stream()
-                            .filter(t -> t.hasTag(UNDETVAR))
-                            .forEach(t -> ((UndetVar)t).setThrow());
+                    if(!checkExConstraints(inferredThrownTypes, lambdaType.getThrownTypes(), resultInfo.checkContext.inferenceContext())) {
+                        log.error(that, Errors.IncompatibleThrownTypesInMref(lambdaType.getThrownTypes()));
+                    }
                 }
 
                 checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, currentTarget);
@@ -3111,15 +3106,70 @@
         }
 
         if (!speculativeAttr) {
-            List<Type> thrownTypes = inferenceContext.asUndetVars(descriptor.getThrownTypes());
-            if (chk.unhandled(refType.getThrownTypes(), thrownTypes).nonEmpty()) {
+            if (!checkExConstraints(refType.getThrownTypes(), descriptor.getThrownTypes(), inferenceContext)) {
                 log.error(tree, Errors.IncompatibleThrownTypesInMref(refType.getThrownTypes()));
             }
-            //18.2.5: "In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej"
-            thrownTypes.stream()
-                    .filter(t -> t.hasTag(UNDETVAR))
-                    .forEach(t -> ((UndetVar)t).setThrow());
-        }
+        }
+    }
+
+    boolean checkExConstraints(
+            List<Type> thrownByFuncExpr,
+            List<Type> thrownAtFuncType,
+            InferenceContext inferenceContext) {
+        /** 18.2.5: Otherwise, let E1, ..., En be the types in the function type's throws clause that
+         *  are not proper types
+         */
+        List<Type> nonProperList = thrownAtFuncType.stream()
+                .filter(e -> inferenceContext.free(e)).collect(List.collector());
+        List<Type> properList = thrownAtFuncType.diff(nonProperList);
+
+        /** Let X1,...,Xm be the checked exception types that the lambda body can throw or
+         *  in the throws clause of the invocation type of the method reference's compile-time
+         *  declaration
+         */
+        List<Type> checkedList = thrownByFuncExpr.stream()
+                .filter(e -> chk.isChecked(e)).collect(List.collector());
+
+        /** If n = 0 (the function type's throws clause consists only of proper types), then
+         *  if there exists some i (1 <= i <= m) such that Xi is not a subtype of any proper type
+         *  in the throws clause, the constraint reduces to false; otherwise, the constraint
+         *  reduces to true
+         */
+        ListBuffer<Type> uncaughtByProperTypes = new ListBuffer<>();
+        for (Type checked : checkedList) {
+            boolean isSubtype = false;
+            for (Type proper : properList) {
+                if (types.isSubtype(checked, proper)) {
+                    isSubtype = true;
+                    break;
+                }
+            }
+            if (!isSubtype) {
+                uncaughtByProperTypes.add(checked);
+            }
+        }
+
+        if (nonProperList.isEmpty() && !uncaughtByProperTypes.isEmpty()) {
+            return false;
+        }
+
+        /** If n > 0, the constraint reduces to a set of subtyping constraints:
+         *  for all i (1 <= i <= m), if Xi is not a subtype of any proper type in the
+         *  throws clause, then the constraints include, for all j (1 <= j <= n), <Xi <: Ej>
+         */
+        List<Type> nonProperAsUndet = inferenceContext.asUndetVars(nonProperList);
+        uncaughtByProperTypes.forEach(checkedEx -> {
+            nonProperAsUndet.forEach(nonProper -> {
+                types.isSubtype(checkedEx, nonProper);
+            });
+        });
+
+        /** In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej
+         */
+        nonProperAsUndet.stream()
+                .filter(t -> t.hasTag(UNDETVAR))
+                .forEach(t -> ((UndetVar)t).setThrow());
+        return true;
     }
 
     /**