type equality constraint: accept unbounded/extends wildcards pair; reject unbounded/super

This commit is contained in:
Anna Kozlova
2014-01-31 21:41:13 +04:00
parent 2070864b80
commit 4444fc1126
3 changed files with 94 additions and 13 deletions
@@ -55,11 +55,12 @@ public class TypeEqualityConstraint implements ConstraintFormula {
if (myT instanceof PsiClassType && myS instanceof PsiClassType) {
final PsiClassType.ClassResolveResult tResult = ((PsiClassType)myT).resolveGenerics();
final PsiClassType.ClassResolveResult sResult = ((PsiClassType)myS).resolveGenerics();
final PsiClass C = tResult.getElement();
if (C == sResult.getElement() && C != null) {
final PsiClass tClass = tResult.getElement();
//equal erasure
if (tClass != null && tClass.equals(sResult.getElement())) {
final PsiSubstitutor tSubstitutor = tResult.getSubstitutor();
final PsiSubstitutor sSubstitutor = sResult.getSubstitutor();
for (PsiTypeParameter typeParameter : C.getTypeParameters()) {
for (PsiTypeParameter typeParameter : tClass.getTypeParameters()) {
final PsiType tSubstituted = tSubstitutor.substitute(typeParameter);
final PsiType sSubstituted = sSubstitutor.substitute(typeParameter);
if (tSubstituted != null && sSubstituted != null) {
@@ -73,16 +74,6 @@ public class TypeEqualityConstraint implements ConstraintFormula {
constraints.add(new TypeEqualityConstraint(((PsiArrayType)myT).getComponentType(), ((PsiArrayType)myS).getComponentType()));
return true;
}
if (myT instanceof PsiIntersectionType && myS instanceof PsiIntersectionType) {
final PsiType[] tConjuncts = ((PsiIntersectionType)myT).getConjuncts();
final PsiType[] sConjuncts = ((PsiIntersectionType)myS).getConjuncts();
if (sConjuncts.length == tConjuncts.length) {
for (int i = 0; i < sConjuncts.length; i++) {
constraints.add(new TypeEqualityConstraint(tConjuncts[i], sConjuncts[i]));
}
return true;
}
}
if (myT instanceof PsiWildcardType && myS instanceof PsiWildcardType) {
final PsiType tBound = ((PsiWildcardType)myT).getBound();
@@ -90,6 +81,18 @@ public class TypeEqualityConstraint implements ConstraintFormula {
if (tBound == null && sBound == null) return true;
if (sBound == null && ((PsiWildcardType)myT).isExtends()) {
//extends bound of "?" (Object)
constraints.add(new TypeEqualityConstraint(((PsiWildcardType)myS).getExtendsBound(), tBound));
return true;
}
if (tBound == null && ((PsiWildcardType)myS).isExtends()) {
//extends bound of "?" (Object)
constraints.add(new TypeEqualityConstraint(((PsiWildcardType)myT).getExtendsBound(), sBound));
return true;
}
if (((PsiWildcardType)myT).isExtends() && ((PsiWildcardType)myS).isExtends() ||
((PsiWildcardType)myT).isSuper() && ((PsiWildcardType)myS).isSuper()) {
@@ -0,0 +1,37 @@
public class SampleExtendsWildcard {
public void highlightsTheBug(Stream<String> stream) {
stream.flatMap((Block<?> sink, String element) -> {});
}
public interface Block<B> {
void apply(B t);
}
public interface Stream<S> {
<R> Stream<R> flatMap(FlatMapper<? super S, R> mapper);
}
public interface FlatMapper<F, R> {
void flatMapInto(Block<? extends R> sink, F element);
}
}
class SampleSuperWildcard {
public void highlightsTheBug(Stream<String> stream) {
stream.flatMap((<error descr="Incompatible parameter types in lambda expression">Block<?> sink</error>, String element) -> {});
}
public interface Block<B> {
void apply(B t);
}
public interface Stream<S> {
<R> Stream<R> flatMap(FlatMapper<? super S, R> mapper);
}
public interface FlatMapper<F, R> {
void flatMapInto(Block<? super R> sink, F element);
}
}
@@ -0,0 +1,41 @@
/*
* 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.Sdk;
import com.intellij.testFramework.IdeaTestUtil;
import org.jetbrains.annotations.NonNls;
/**
* Created by anna on 1/31/14.
*/
public class ConstraintsInferenceMiscTest extends LightDaemonAnalyzerTestCase {
@NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/constraints";
public void testEqualityUnboundWildcard() throws Exception {
doTest(false);
}
private void doTest(final boolean checkWarnings) {
doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
}
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk18();
}
}