2 * Copyright 2000-2013 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.psi.impl.source.resolve.graphInference.constraints;
18 import com.intellij.psi.*;
19 import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
20 import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
21 import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable;
22 import com.intellij.psi.util.PsiUtil;
23 import org.jetbrains.annotations.Nullable;
25 import java.util.HashSet;
27 import java.util.stream.Collectors;
28 import java.util.stream.Stream;
30 public abstract class InputOutputConstraintFormula implements ConstraintFormula {
33 protected InputOutputConstraintFormula(PsiType t) {
37 public abstract PsiExpression getExpression();
38 protected abstract InputOutputConstraintFormula createSelfConstraint(PsiType type, PsiExpression expression);
39 protected abstract void collectReturnTypeVariables(InferenceSession session,
40 PsiExpression psiExpression,
42 Set<InferenceVariable> result);
44 public Set<InferenceVariable> getInputVariables(InferenceSession session) {
45 final PsiExpression psiExpression = getExpression();
46 final PsiType type = myT;
47 if (psiExpression instanceof PsiFunctionalExpression) {
48 final InferenceVariable inferenceVariable = session.getInferenceVariable(type);
49 if (inferenceVariable != null) {
50 final HashSet<InferenceVariable> result = new HashSet<>();
51 result.add(inferenceVariable);
54 if (LambdaUtil.isFunctionalType(type)) {
55 final PsiType functionType =
56 psiExpression instanceof PsiLambdaExpression
57 ? FunctionalInterfaceParameterizationUtil.getGroundTargetType(type, (PsiLambdaExpression)psiExpression, false)
59 final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionType);
60 final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
61 if (interfaceMethod != null) {
63 final Set<InferenceVariable> result = new HashSet<>();
64 final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult);
65 if (psiExpression instanceof PsiLambdaExpression && !((PsiLambdaExpression)psiExpression).hasFormalParameterTypes() ||
66 psiExpression instanceof PsiMethodReferenceExpression && !((PsiMethodReferenceExpression)psiExpression).isExact()) {
67 for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
68 session.collectDependencies(substitutor.substitute(parameter.getType()), result);
72 final PsiType returnType = interfaceMethod.getReturnType();
73 if (returnType != null) {
74 collectReturnTypeVariables(session, psiExpression, substitutor.substitute(returnType), result);
82 if (psiExpression instanceof PsiParenthesizedExpression) {
83 final PsiExpression expression = ((PsiParenthesizedExpression)psiExpression).getExpression();
84 return expression != null ? createSelfConstraint(type, expression).getInputVariables(session) : null;
87 if (psiExpression instanceof PsiConditionalExpression) {
88 final PsiExpression thenExpression = ((PsiConditionalExpression)psiExpression).getThenExpression();
89 final PsiExpression elseExpression = ((PsiConditionalExpression)psiExpression).getElseExpression();
90 final Set<InferenceVariable> thenResult = thenExpression != null ? createSelfConstraint(type, thenExpression).getInputVariables(session) : null;
91 final Set<InferenceVariable> elseResult = elseExpression != null ? createSelfConstraint(type, elseExpression).getInputVariables(session) : null;
92 if (thenResult == null) {
94 } else if (elseResult == null) {
97 thenResult.addAll(elseResult);
102 if (psiExpression instanceof PsiSwitchExpression) {
103 Set<InferenceVariable> variables =
104 PsiUtil.getSwitchResultExpressions((PsiSwitchExpression)psiExpression).stream().flatMap(expression -> {
105 Set<InferenceVariable> inputVariables = createSelfConstraint(type, expression).getInputVariables(session);
106 return inputVariables != null ? inputVariables.stream() : Stream.empty();
107 }).collect(Collectors.toSet());
108 return variables.isEmpty() ? null : variables;
115 public Set<InferenceVariable> getOutputVariables(Set<InferenceVariable> inputVariables, InferenceSession session) {
116 final HashSet<InferenceVariable> mentionedVariables = new HashSet<>();
117 session.collectDependencies(myT, mentionedVariables);
118 if (inputVariables != null) {
119 mentionedVariables.removeAll(inputVariables);
121 return mentionedVariables.isEmpty() ? null : mentionedVariables;
125 public void apply(PsiSubstitutor substitutor, boolean cache) {
126 myT = substitutor.substitute(myT);
129 public PsiType getCurrentType() {
134 public String toString() {
135 return getExpression().getText() + " -> " + myT.getPresentableText();