2513 |
2513 |
2514 if (!isSpeculativeRound) { |
2514 if (!isSpeculativeRound) { |
2515 //add thrown types as bounds to the thrown types free variables if needed: |
2515 //add thrown types as bounds to the thrown types free variables if needed: |
2516 if (resultInfo.checkContext.inferenceContext().free(lambdaType.getThrownTypes())) { |
2516 if (resultInfo.checkContext.inferenceContext().free(lambdaType.getThrownTypes())) { |
2517 List<Type> inferredThrownTypes = flow.analyzeLambdaThrownTypes(env, that, make); |
2517 List<Type> inferredThrownTypes = flow.analyzeLambdaThrownTypes(env, that, make); |
2518 List<Type> thrownTypes = resultInfo.checkContext.inferenceContext().asUndetVars(lambdaType.getThrownTypes()); |
2518 if(!checkExConstraints(inferredThrownTypes, lambdaType.getThrownTypes(), resultInfo.checkContext.inferenceContext())) { |
2519 |
2519 log.error(that, Errors.IncompatibleThrownTypesInMref(lambdaType.getThrownTypes())); |
2520 chk.unhandled(inferredThrownTypes, thrownTypes); |
2520 } |
2521 |
|
2522 //18.2.5: "In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej" |
|
2523 thrownTypes.stream() |
|
2524 .filter(t -> t.hasTag(UNDETVAR)) |
|
2525 .forEach(t -> ((UndetVar)t).setThrow()); |
|
2526 } |
2521 } |
2527 |
2522 |
2528 checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, currentTarget); |
2523 checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, currentTarget); |
2529 } |
2524 } |
2530 result = check(that, currentTarget, KindSelector.VAL, resultInfo); |
2525 result = check(that, currentTarget, KindSelector.VAL, resultInfo); |
3109 tree.referentType = refType; |
3104 tree.referentType = refType; |
3110 } |
3105 } |
3111 } |
3106 } |
3112 |
3107 |
3113 if (!speculativeAttr) { |
3108 if (!speculativeAttr) { |
3114 List<Type> thrownTypes = inferenceContext.asUndetVars(descriptor.getThrownTypes()); |
3109 if (!checkExConstraints(refType.getThrownTypes(), descriptor.getThrownTypes(), inferenceContext)) { |
3115 if (chk.unhandled(refType.getThrownTypes(), thrownTypes).nonEmpty()) { |
|
3116 log.error(tree, Errors.IncompatibleThrownTypesInMref(refType.getThrownTypes())); |
3110 log.error(tree, Errors.IncompatibleThrownTypesInMref(refType.getThrownTypes())); |
3117 } |
3111 } |
3118 //18.2.5: "In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej" |
3112 } |
3119 thrownTypes.stream() |
3113 } |
3120 .filter(t -> t.hasTag(UNDETVAR)) |
3114 |
3121 .forEach(t -> ((UndetVar)t).setThrow()); |
3115 boolean checkExConstraints( |
3122 } |
3116 List<Type> thrownByFuncExpr, |
|
3117 List<Type> thrownAtFuncType, |
|
3118 InferenceContext inferenceContext) { |
|
3119 /** 18.2.5: Otherwise, let E1, ..., En be the types in the function type's throws clause that |
|
3120 * are not proper types |
|
3121 */ |
|
3122 List<Type> nonProperList = thrownAtFuncType.stream() |
|
3123 .filter(e -> inferenceContext.free(e)).collect(List.collector()); |
|
3124 List<Type> properList = thrownAtFuncType.diff(nonProperList); |
|
3125 |
|
3126 /** Let X1,...,Xm be the checked exception types that the lambda body can throw or |
|
3127 * in the throws clause of the invocation type of the method reference's compile-time |
|
3128 * declaration |
|
3129 */ |
|
3130 List<Type> checkedList = thrownByFuncExpr.stream() |
|
3131 .filter(e -> chk.isChecked(e)).collect(List.collector()); |
|
3132 |
|
3133 /** If n = 0 (the function type's throws clause consists only of proper types), then |
|
3134 * if there exists some i (1 <= i <= m) such that Xi is not a subtype of any proper type |
|
3135 * in the throws clause, the constraint reduces to false; otherwise, the constraint |
|
3136 * reduces to true |
|
3137 */ |
|
3138 ListBuffer<Type> uncaughtByProperTypes = new ListBuffer<>(); |
|
3139 for (Type checked : checkedList) { |
|
3140 boolean isSubtype = false; |
|
3141 for (Type proper : properList) { |
|
3142 if (types.isSubtype(checked, proper)) { |
|
3143 isSubtype = true; |
|
3144 break; |
|
3145 } |
|
3146 } |
|
3147 if (!isSubtype) { |
|
3148 uncaughtByProperTypes.add(checked); |
|
3149 } |
|
3150 } |
|
3151 |
|
3152 if (nonProperList.isEmpty() && !uncaughtByProperTypes.isEmpty()) { |
|
3153 return false; |
|
3154 } |
|
3155 |
|
3156 /** If n > 0, the constraint reduces to a set of subtyping constraints: |
|
3157 * for all i (1 <= i <= m), if Xi is not a subtype of any proper type in the |
|
3158 * throws clause, then the constraints include, for all j (1 <= j <= n), <Xi <: Ej> |
|
3159 */ |
|
3160 List<Type> nonProperAsUndet = inferenceContext.asUndetVars(nonProperList); |
|
3161 uncaughtByProperTypes.forEach(checkedEx -> { |
|
3162 nonProperAsUndet.forEach(nonProper -> { |
|
3163 types.isSubtype(checkedEx, nonProper); |
|
3164 }); |
|
3165 }); |
|
3166 |
|
3167 /** In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej |
|
3168 */ |
|
3169 nonProperAsUndet.stream() |
|
3170 .filter(t -> t.hasTag(UNDETVAR)) |
|
3171 .forEach(t -> ((UndetVar)t).setThrow()); |
|
3172 return true; |
3123 } |
3173 } |
3124 |
3174 |
3125 /** |
3175 /** |
3126 * Set functional type info on the underlying AST. Note: as the target descriptor |
3176 * Set functional type info on the underlying AST. Note: as the target descriptor |
3127 * might contain inference variables, we might need to register an hook in the |
3177 * might contain inference variables, we might need to register an hook in the |