boolean (PsiExpression arg, @Nullable InferenceSession session, PsiMethod sInterfaceMethod, PsiSubstitutor sSubstitutor, PsiMethod tInterfaceMethod, PsiSubstitutor tSubstitutor) { if (arg instanceof PsiLambdaExpression && ((PsiLambdaExpression)arg).hasFormalParameterTypes()) { final PsiType sReturnType = sSubstitutor.substitute(sInterfaceMethod.getReturnType()); final PsiType tReturnType = tSubstitutor.substitute(tInterfaceMethod.getReturnType()); if (PsiTypes.voidType().equals(tReturnType)) { return true; } final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)arg); if (sReturnType instanceof PsiClassType && tReturnType instanceof PsiClassType && LambdaUtil.isFunctionalType(sReturnType) && LambdaUtil.isFunctionalType(tReturnType) && !TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(sReturnType), TypeConversionUtil.erasure(tReturnType)) && !TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(tReturnType), TypeConversionUtil.erasure(sReturnType))) { //Otherwise, if R1 and R2 are functional interface types, and neither interface is a subinterface of the other, //then these rules are applied recursively to R1 and R2, for each result expression in expi. if (!isFunctionalTypeMoreSpecific(sReturnType, tReturnType, session, returnExpressions.toArray(PsiExpression.EMPTY_ARRAY))) { return false; } } else { final boolean sPrimitive = sReturnType instanceof PsiPrimitiveType && !PsiTypes.voidType().equals(sReturnType); final boolean tPrimitive = tReturnType instanceof PsiPrimitiveType && !PsiTypes.voidType().equals(tReturnType); if (sPrimitive ^ tPrimitive) { for (PsiExpression returnExpression : returnExpressions) { if (!PsiPolyExpressionUtil.isPolyExpression(returnExpression)) { final PsiType returnExpressionType = returnExpression.getType(); if (sPrimitive) { if (!(returnExpressionType instanceof PsiPrimitiveType)) { return false; } } else { if (!(returnExpressionType instanceof PsiClassType)) { return false; } } } else if (sPrimitive) { return false; } } return true; } if (session != null) { session.addConstraint(new StrictSubtypingConstraint(tReturnType, sReturnType)); return true; } else { return sReturnType != null && tReturnType != null && TypeConversionUtil.isAssignable(tReturnType, sReturnType); } } } if (arg instanceof PsiMethodReferenceExpression && ((PsiMethodReferenceExpression)arg).isExact()) { final PsiParameter[] sParameters = sInterfaceMethod.getParameterList().getParameters(); final PsiParameter[] tParameters = tInterfaceMethod.getParameterList().getParameters(); if (sParameters.length != tParameters.length) { LOG.error("s: " + sInterfaceMethod.getParameterList().getText() + "; t: " + tInterfaceMethod.getParameterList().getText()); } for (int i = 0; i < tParameters.length; i++) { final PsiType tSubstituted = tSubstitutor.substitute(tParameters[i].getType()); final PsiType sSubstituted = sSubstitutor.substitute(sParameters[i].getType()); if (session != null) { session.addConstraint(new TypeEqualityConstraint(tSubstituted, sSubstituted)); } else { if (!Comparing.equal(tSubstituted, sSubstituted)) { return false; } } } final PsiType sReturnType = sSubstitutor.substitute(sInterfaceMethod.getReturnType()); final PsiType tReturnType = tSubstitutor.substitute(tInterfaceMethod.getReturnType()); if (PsiTypes.voidType().equals(tReturnType)) { return true; } final boolean sPrimitive = sReturnType instanceof PsiPrimitiveType && !PsiTypes.voidType().equals(sReturnType); final boolean tPrimitive = tReturnType instanceof PsiPrimitiveType && !PsiTypes.voidType().equals(tReturnType); if (sPrimitive ^ tPrimitive) { final PsiMember member = ((PsiMethodReferenceExpression)arg).getPotentiallyApplicableMember(); LOG.assertTrue(member != null, arg); if (member instanceof PsiMethod) { final PsiType methodReturnType = ((PsiMethod)member).getReturnType(); if (sPrimitive && methodReturnType instanceof PsiPrimitiveType && !PsiTypes.voidType().equals(methodReturnType) || tPrimitive && methodReturnType instanceof PsiClassType) { return true; } } return false; } if (session != null) { session.addConstraint(new StrictSubtypingConstraint(tReturnType, sReturnType)); return true; } else { return sReturnType != null && tReturnType != null && TypeConversionUtil.isAssignable(tReturnType, sReturnType); } } if (arg instanceof PsiParenthesizedExpression) { return argConstraints(((PsiParenthesizedExpression)arg).getExpression(), session, sInterfaceMethod, sSubstitutor, tInterfaceMethod, tSubstitutor); } if (arg instanceof PsiConditionalExpression) { final PsiExpression thenExpression = ((PsiConditionalExpression)arg).getThenExpression(); final PsiExpression elseExpression = ((PsiConditionalExpression)arg).getElseExpression(); return argConstraints(thenExpression, session, sInterfaceMethod, sSubstitutor, tInterfaceMethod, tSubstitutor) && argConstraints(elseExpression, session, sInterfaceMethod, sSubstitutor, tInterfaceMethod, tSubstitutor); } if (arg instanceof PsiSwitchExpression) { return PsiUtil.getSwitchResultExpressions((PsiSwitchExpression)arg).stream() .allMatch(resultExpression -> argConstraints(resultExpression, session, sInterfaceMethod, sSubstitutor, tInterfaceMethod, tSubstitutor)); } return false; }