From a047666d5792541f0817d90fd6ab49d472bbd062 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 28 Feb 2014 16:03:50 +0100 Subject: [PATCH] new inference: non wildcard parametrization against the spec --- .../src/com/intellij/psi/GenericsUtil.java | 8 ++ .../com/intellij/psi/PsiIntersectionType.java | 3 +- ...nctionalInterfaceParameterizationUtil.java | 36 +++--- .../NonWildcardParametrization.java | 108 ++++++++++++++++++ ...ionalTypeWildcardParameterizationTest.java | 40 +++++++ 5 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index 8c36cfae1b88..577d38a30a15 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -519,6 +519,14 @@ public class GenericsUtil { else if (type instanceof PsiArrayType) { return checkNotAssignable(bound, type, true); } + else if (type instanceof PsiIntersectionType) { + for (PsiType psiType : ((PsiIntersectionType)type).getConjuncts()) { + if (!checkNotInBounds(psiType, bound, uncheckedConversionByDefault)) { + return false; + } + } + return true; + } return false; } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java index 215bb86b2b81..5f5d6d7ef8dc 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java @@ -78,7 +78,8 @@ public class PsiIntersectionType extends PsiType { for (PsiType existing : array) { if (type != existing) { final boolean allowUncheckedConversion = type instanceof PsiClassType && ((PsiClassType)type).isRaw(); - if (TypeConversionUtil.isAssignable(type, existing, allowUncheckedConversion)) { + if (TypeConversionUtil.isAssignable(GenericsUtil.eliminateWildcards(type), + GenericsUtil.eliminateWildcards(existing), allowUncheckedConversion)) { iterator.remove(); break; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java index a52ea73a18d5..47eafa49fcfa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqualityConstraint; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; @@ -169,27 +168,32 @@ public class FunctionalInterfaceParameterizationUtil { for (int i = 0; i < parameters.length; i++) { PsiType paramType = parameters[i]; if (paramType instanceof PsiWildcardType) { - final PsiClassType[] extendsListTypes = typeParameters[i].getExtendsListTypes(); - final PsiClassType Bi = extendsListTypes.length > 0 ? extendsListTypes[0] - : PsiType.getJavaLangObject(psiClass.getManager(), - GlobalSearchScope.allScope(psiClass.getProject())); - if (PsiPolyExpressionUtil.mentionsTypeParameters(Bi, typeParametersSet)) { - return null; + final PsiType bound = GenericsUtil.eliminateWildcards(((PsiWildcardType)paramType).getBound(), false); + if (((PsiWildcardType)paramType).isSuper()) { + newParameters[i] = bound; } - - final PsiType bound = ((PsiWildcardType)paramType).getBound(); - if (bound == null) { - newParameters[i] = Bi; - } else if (((PsiWildcardType)paramType).isExtends()){ - newParameters[i] = GenericsUtil.getGreatestLowerBound(Bi, GenericsUtil.eliminateWildcards(bound, false)); - } else { - newParameters[i] = GenericsUtil.eliminateWildcards(bound, false); + else { + newParameters[i] = bound != null ? bound : PsiType.getJavaLangObject(psiClass.getManager(), psiClassType.getResolveScope()); + for (PsiClassType paramBound : typeParameters[i].getExtendsListTypes()) { + if (!PsiPolyExpressionUtil.mentionsTypeParameters(paramBound, typeParametersSet)) { + newParameters[i] = GenericsUtil.getGreatestLowerBound(paramBound, newParameters[i]); + } + } } } else { newParameters[i] = paramType; } } - return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + + if (!isWellFormed(psiClass, typeParameters, newParameters)) { + return null; + } + + final PsiClassType parameterization = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + if (!psiClassType.isAssignableFrom(parameterization)) { + return null; + } + return parameterization; } return null; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java new file mode 100644 index 000000000000..fa9df550e936 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization/NonWildcardParametrization.java @@ -0,0 +1,108 @@ +import java.util.List; + +class SimpleDependency { + + interface I { + R m(); + } + + { + I k = () -> null; + I k1 = () -> null; + I, List> k2 = () -> null; + I, ? extends List> k3 = () -> null; + I, ? extends List> k4 = () -> null; + I, List> k5 = () -> null; + I, ? extends List> k6 = () -> null; + + I s = () -> null; + I, List> s1 = () -> null; + } +} + +class NoDependency { + interface I { + T m(); + } + + { + I k = () -> null; + } +} + +class ExtendsList { + interface I, T> { + R m(); + } + + { + I n = () -> null; + I n1 = () -> null; + I n2 = () -> null; + + + I, String> e1 = () -> null; + I, ?> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, ? extends String> e4 = () -> null; + + I, ? extends String> s1 = () -> null; + I, String> s2 = () -> null; + } +} + +class MultipleBounds { + interface I & Comparable, T> { + R m(); + } + + interface LC extends List, Comparable {} + + { + I n = () -> null; + + I, ? extends String> e1 = () -> null; + I, ? extends String> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, String> e4 = () -> null; + I, String> e5 = () -> null; + } +} + +class FirstIndependentBound { + interface I & Comparable, T> { + R m(); + } + + interface LC extends List, Comparable {} + + { + I n = () -> null; + + I, ? extends String> e1 = () -> null; + I, ? extends String> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, String> e4 = () -> null; + I, String> e5 = () -> null; + } +} + + +class SecondIndependentBound { + interface I & Comparable, T> { + R m(); + } + + interface LC extends List, Comparable {} + + { + I n = () -> null; + + I, ? extends String> e1 = () -> null; + I, ? extends String> e2 = () -> null; + I, ? extends String> e3 = () -> null; + I, String> e4 = () -> null; + I, String> e5 = () -> null; + I, ? extends String> e6 = () -> null; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java new file mode 100644 index 000000000000..4fe2aa494f00 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.lambda; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NonNls; + +public class FunctionalTypeWildcardParameterizationTest extends LightDaemonAnalyzerTestCase { + @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/wildcardParametrization"; + + public void testNonWildcardParametrization() throws Exception { + doTest(); + } + + private void doTest() { + IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable()); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false); + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +}