boolean (final InferenceSession session, List<? super ConstraintFormula> constraints) { if (!PsiPolyExpressionUtil.isPolyExpression(myExpression)) { return true; } PsiType myT = getCurrentType(); if (myExpression instanceof PsiParenthesizedExpression) { constraints.add(new CheckedExceptionCompatibilityConstraint(((PsiParenthesizedExpression)myExpression).getExpression(), myT)); return true; } if (myExpression instanceof PsiConditionalExpression) { final PsiExpression thenExpression = ((PsiConditionalExpression)myExpression).getThenExpression(); if (thenExpression != null) { constraints.add(new CheckedExceptionCompatibilityConstraint(thenExpression, myT)); } final PsiExpression elseExpression = ((PsiConditionalExpression)myExpression).getElseExpression(); if (elseExpression != null) { constraints.add(new CheckedExceptionCompatibilityConstraint(elseExpression, myT)); } return true; } if (myExpression instanceof PsiLambdaExpression || myExpression instanceof PsiMethodReferenceExpression) { if (!LambdaUtil.isFunctionalType(myT)) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.not.a.functional.interface", session.getPresentableText(myT))); return false; } final PsiType groundTargetType = myExpression instanceof PsiLambdaExpression ? FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT, (PsiLambdaExpression)myExpression, false) : FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(groundTargetType); if (interfaceMethod == null) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.no.valid.function.type.found", session.getPresentableText(myT))); return false; } final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, PsiUtil.resolveGenericsClassInType(groundTargetType)); if (myExpression instanceof PsiLambdaExpression && !((PsiLambdaExpression)myExpression).hasFormalParameterTypes() || myExpression instanceof PsiMethodReferenceExpression && !((PsiMethodReferenceExpression)myExpression).isExact()) { for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) { final PsiType type = substitutor.substitute(parameter.getType()); if (!session.isProperType(type)) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.parameter.type.is.not.yet.inferred", session.getPresentableText(type))); return false; } } } final PsiType returnType = interfaceMethod.getReturnType(); if (myExpression instanceof PsiLambdaExpression || !((PsiMethodReferenceExpression)myExpression).isExact()) { final PsiType type = substitutor.substitute(returnType); if (!session.isProperType(type)) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.return.type.is.not.yet.inferred", session.getPresentableText(type))); return false; } } final List<PsiType> expectedThrownTypes = ContainerUtil.map(interfaceMethod.getThrowsList().getReferencedTypes(), type -> session.substituteWithInferenceVariables(substitutor.substitute(type))); final List<PsiType> expectedNonProperThrownTypes = new ArrayList<>(); for (PsiType type : expectedThrownTypes) { if (!session.isProperType(type)) { expectedNonProperThrownTypes.add(type); } } final List<PsiType> thrownTypes = new ArrayList<>(); final PsiElement body = myExpression instanceof PsiLambdaExpression ? ((PsiLambdaExpression)myExpression).getBody() : myExpression; if (body != null) { final List<PsiClassType> exceptions = ExceptionUtil.getUnhandledExceptions(new PsiElement[] {body}); thrownTypes.addAll(ContainerUtil.filter(exceptions, type -> !ExceptionUtil.isUncheckedException(type))); } if (expectedNonProperThrownTypes.isEmpty()) { for (PsiType thrownType : thrownTypes) { if (!isAddressed(expectedThrownTypes, thrownType)) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.unhandled.exception", session.getPresentableText(thrownType))); return false; } } } else { final ArrayList<PsiType> expectedProperTypes = new ArrayList<>(expectedThrownTypes); expectedProperTypes.removeAll(expectedNonProperThrownTypes); for (PsiType thrownType : thrownTypes) { if (!isAddressed(expectedProperTypes, thrownType)) { for (PsiType expectedNonProperThrownType : expectedNonProperThrownTypes) { constraints.add(new StrictSubtypingConstraint(expectedNonProperThrownType, thrownType)); } } } for (PsiType expectedNonProperThrownType : expectedNonProperThrownTypes) { final InferenceVariable variable = session.getInferenceVariable(expectedNonProperThrownType); //could be null for invalid code if (variable != null) { variable.setThrownBound(); } } } } return true; }