PsiSubstitutor (final PsiParameter @NotNull [] parameters, final PsiExpression @NotNull [] arguments, @NotNull final PsiCall parent, @NotNull final MethodCandidateInfo currentMethod, @NotNull final InferenceSession parentSession) { final List<String> errorMessages = parentSession.getIncompatibleErrorMessages(); if (errorMessages != null && !MethodCandidateInfo.isOverloadCheck()) { //for lambda parameter type calculation, the parent inference may contain errors due to skipping that lambda constraints //but the type of the lambda parameter should not depend on the lambda body, thus the nested inference may still provide valid results return null; } final CompoundInitialState compoundInitialState = createState(parentSession); InitialInferenceState initialInferenceState = compoundInitialState.getInitialState(parent); if (initialInferenceState != null) { InferenceSession childSession = new InferenceSession(initialInferenceState, parentSession.getInferencePolicy()); return childSession.collectAdditionalAndInfer(parameters, arguments, currentMethod, compoundInitialState.getInitialSubstitutor()); } //we do not investigate lambda return expressions when lambda's return type is already inferred (proper) //this way all calls from lambda's return expressions won't appear in nested sessions PsiElement gParent = PsiUtil.skipParenthesizedExprUp(parent.getParent()); //find the nearest parent which appears in the map and start inference with a provided target type for a nested lambda while (true) { if (gParent instanceof PsiReturnStatement) { //process code block lambda gParent = PsiTreeUtil.getParentOfType(gParent, PsiLambdaExpression.class); } if (gParent instanceof PsiConditionalExpression) { gParent = PsiUtil.skipParenthesizedExprUp(gParent.getParent()); } if (gParent instanceof PsiLambdaExpression) { final PsiCall call = PsiTreeUtil.getParentOfType(gParent, PsiCall.class); if (call != null) { initialInferenceState = compoundInitialState.getInitialState(call); if (initialInferenceState != null) { final PsiExpressionList argumentList = call.getArgumentList(); final int idx = argumentList != null ? LambdaUtil.getLambdaIdx(argumentList, gParent) : -1; final JavaResolveResult result = PsiDiamondType.getDiamondsAwareResolveResult(call); final PsiElement method = result.getElement(); if (method instanceof PsiMethod && idx > -1) { final PsiParameter[] methodParameters = ((PsiMethod)method).getParameterList().getParameters(); if (methodParameters.length == 0) { break; } //one of the grand parents were found in the top inference session //start from it as it is the top level call InferenceSession sessionInsideLambda = new InferenceSession(initialInferenceState, parentSession.getInferencePolicy()); sessionInsideLambda.collectAdditionalAndInfer(methodParameters, argumentList.getExpressions(), ((MethodCandidateInfo)result), compoundInitialState.getInitialSubstitutor()); return inferNested(parameters, arguments, parent, currentMethod, sessionInsideLambda); } } else { gParent = PsiUtil.skipParenthesizedExprUp(call.getParent()); continue; } } } break; } return null; }