constructor reference: don't ignore constructor parameters during method reference...
[idea/community.git] / java / java-psi-api / src / com / intellij / psi / GenericsUtil.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.psi;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.util.Comparing;
20 import com.intellij.openapi.util.Couple;
21 import com.intellij.openapi.util.Pair;
22 import com.intellij.psi.search.GlobalSearchScope;
23 import com.intellij.psi.util.*;
24 import com.intellij.util.containers.ContainerUtil;
25 import org.jetbrains.annotations.Contract;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
28
29 import java.util.*;
30
31 /**
32  * @author ven
33  */
34 public class GenericsUtil {
35
36   private static final Logger LOG = Logger.getInstance(GenericsUtil.class);
37
38   private GenericsUtil() {}
39
40   public static PsiType getGreatestLowerBound(@Nullable PsiType type1, @Nullable PsiType type2) {
41     if (type1 == null || type2 == null) return null;
42     return PsiIntersectionType.createIntersection(type1, type2);
43   }
44
45   @Nullable
46   public static PsiType getLeastUpperBound(PsiType type1, PsiType type2, PsiManager manager) {
47     if (TypeConversionUtil.isPrimitiveAndNotNull(type1) || TypeConversionUtil.isPrimitiveAndNotNull(type2)) return null;
48     if (TypeConversionUtil.isNullType(type1)) return type2;
49     if (TypeConversionUtil.isNullType(type2)) return type1;
50     if (Comparing.equal(type1, type2)) return type1;
51     return getLeastUpperBound(type1, type2, new LinkedHashSet<>(), manager);
52   }
53
54   @NotNull
55   private static PsiType getLeastUpperBound(PsiType type1, PsiType type2, Set<Couple<PsiType>> compared, PsiManager manager) {
56     if (type1 instanceof PsiCapturedWildcardType) {
57       return getLeastUpperBound(((PsiCapturedWildcardType)type1).getUpperBound(), type2, compared, manager);
58     }
59     if (type2 instanceof PsiCapturedWildcardType) {
60       return getLeastUpperBound(type1, ((PsiCapturedWildcardType)type2).getUpperBound(), compared, manager);
61     }
62
63     if (type1 instanceof PsiWildcardType) {
64       return getLeastUpperBound(((PsiWildcardType)type1).getExtendsBound(), type2, compared, manager);
65     }
66     if (type2 instanceof PsiWildcardType) {
67       return getLeastUpperBound(type1, ((PsiWildcardType)type2).getExtendsBound(), compared, manager);
68     }
69
70     if (type1 instanceof PsiArrayType && type2 instanceof PsiArrayType) {
71       final PsiType componentType1 = ((PsiArrayType)type1).getComponentType();
72       final PsiType componentType2 = ((PsiArrayType)type2).getComponentType();
73       final PsiType componentType = getLeastUpperBound(componentType1, componentType2, compared, manager);
74       if ((componentType1 instanceof PsiPrimitiveType ||
75            componentType2 instanceof PsiPrimitiveType) &&
76           componentType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
77         final PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject());
78         final GlobalSearchScope resolveScope = GlobalSearchScope.allScope(manager.getProject());
79         final PsiClassType cloneable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_CLONEABLE, resolveScope);
80         final PsiClassType serializable = factory.createTypeByFQClassName(CommonClassNames.JAVA_IO_SERIALIZABLE, resolveScope);
81         return PsiIntersectionType.createIntersection(componentType, cloneable, serializable);
82       }
83       return componentType.createArrayType();
84     }
85     if (type1 instanceof PsiIntersectionType) {
86       Set<PsiType> newConjuncts = new LinkedHashSet<>();
87       final PsiType[] conjuncts = ((PsiIntersectionType)type1).getConjuncts();
88       for (PsiType type : conjuncts) {
89         newConjuncts.add(getLeastUpperBound(type, type2, compared, manager));
90       }
91       return PsiIntersectionType.createIntersection(newConjuncts.toArray(PsiType.createArray(newConjuncts.size())));
92     }
93     if (type2 instanceof PsiIntersectionType) {
94       return getLeastUpperBound(type2, type1, compared, manager);
95     }
96     if (type1 instanceof PsiClassType && type2 instanceof PsiClassType) {
97       PsiClassType.ClassResolveResult classResolveResult1 = ((PsiClassType)type1).resolveGenerics();
98       PsiClassType.ClassResolveResult classResolveResult2 = ((PsiClassType)type2).resolveGenerics();
99       PsiClass aClass = classResolveResult1.getElement();
100       PsiClass bClass = classResolveResult2.getElement();
101       if (aClass == null || bClass == null) {
102         return PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject()));
103       }
104
105       PsiClass[] supers = getLeastUpperClasses(aClass, bClass);
106       if (supers.length == 0) {
107         return PsiType.getJavaLangObject(manager, aClass.getResolveScope());
108       }
109
110       final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(manager.getProject());
111       PsiClassType[] conjuncts = new PsiClassType[supers.length];
112       Set<Couple<PsiType>> siblings = new HashSet<>();
113       try {
114         for (int i = 0; i < supers.length; i++) {
115           PsiClass aSuper = supers[i];
116           PsiSubstitutor subst1 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, aClass, classResolveResult1.getSubstitutor());
117           PsiSubstitutor subst2 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, bClass, classResolveResult2.getSubstitutor());
118           PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
119
120           final Couple<PsiType> types = Couple.of(elementFactory.createType(aSuper, subst1), elementFactory.createType(aSuper, subst2));
121           boolean skip = compared.contains(types);
122
123           for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aSuper)) {
124             PsiType mapping1 = subst1.substitute(parameter);
125             PsiType mapping2 = subst2.substitute(parameter);
126
127             if (mapping1 != null && mapping2 != null) {
128               if (skip) {
129                 substitutor = substitutor.put(parameter, PsiWildcardType.createUnbounded(manager));
130               }
131               else {
132                 compared.add(types);
133                 try {
134                   PsiType argument = getLeastContainingTypeArgument(mapping1, mapping2, compared, manager);
135                   substitutor = substitutor.put(parameter, argument);
136                 }
137                 finally {
138                   siblings.add(types);
139                 }
140               }
141             }
142             else {
143               substitutor = substitutor.put(parameter, null);
144             }
145           }
146
147           conjuncts[i] = elementFactory.createType(aSuper, substitutor);
148         }
149       }
150       finally {
151         compared.removeAll(siblings);
152       }
153
154       return PsiIntersectionType.createIntersection(conjuncts);
155     }
156     if (type2 instanceof PsiArrayType && !(type1 instanceof PsiArrayType)) {
157       return getLeastUpperBound(type2, type1, compared, manager);
158     }
159     if (type1 instanceof PsiArrayType) {
160       PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject());
161       GlobalSearchScope all = GlobalSearchScope.allScope(manager.getProject());
162       PsiClassType serializable = factory.createTypeByFQClassName(CommonClassNames.JAVA_IO_SERIALIZABLE, all);
163       PsiClassType cloneable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_CLONEABLE, all);
164       PsiType arraySupers = PsiIntersectionType.createIntersection(serializable, cloneable);
165       return getLeastUpperBound(arraySupers, type2, compared, manager);
166     }
167
168     return PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject()));
169   }
170
171   private static PsiType getLeastContainingTypeArgument(PsiType type1,
172                                                         PsiType type2,
173                                                         Set<Couple<PsiType>> compared,
174                                                         PsiManager manager) {
175     if (type1 instanceof PsiWildcardType) {
176       PsiWildcardType wild1 = (PsiWildcardType)type1;
177       final PsiType bound1 = wild1.getBound();
178       if (bound1 == null) return type1;
179       if (type2 instanceof PsiWildcardType) {
180         PsiWildcardType wild2 = (PsiWildcardType)type2;
181         final PsiType bound2 = wild2.getBound();
182         if (bound2 == null) return type2;
183         if (wild1.isExtends() == wild2.isExtends()) {
184           return wild1.isExtends() ?
185                  PsiWildcardType.createExtends(manager, getLeastUpperBound(bound1, bound2, compared, manager)) :
186                  PsiWildcardType.createSuper(manager, getGreatestLowerBound(bound1, bound2));
187         }
188         else {
189           return bound1.equals(bound2) ? bound1 : PsiWildcardType.createUnbounded(manager);
190         }
191       }
192       else {
193         return wild1.isExtends() ? PsiWildcardType.createExtends(manager, getLeastUpperBound(bound1, type2, compared, manager)) :
194                wild1.isSuper() ? PsiWildcardType.createSuper(manager, getGreatestLowerBound(bound1, type2)) :
195                wild1;
196       }
197     }
198     else if (type2 instanceof PsiWildcardType) {
199       return getLeastContainingTypeArgument(type2, type1, compared, manager);
200     }
201     //Done with wildcards
202
203     if (type1.equals(type2)) return type1;
204     return PsiWildcardType.createExtends(manager, getLeastUpperBound(type1, type2, compared, manager));
205   }
206
207   @NotNull
208   public static PsiClass[] getLeastUpperClasses(PsiClass aClass, PsiClass bClass) {
209     if (InheritanceUtil.isInheritorOrSelf(aClass, bClass, true)) return new PsiClass[]{bClass};
210     Set<PsiClass> supers = new LinkedHashSet<>();
211     Set<PsiClass> visited = new HashSet<>();
212     getLeastUpperClassesInner(aClass, bClass, supers, visited);
213     return supers.toArray(PsiClass.EMPTY_ARRAY);
214   }
215
216   private static void getLeastUpperClassesInner(PsiClass aClass, PsiClass bClass, Set<PsiClass> supers, Set<? super PsiClass> visited) {
217     if (bClass.isInheritor(aClass, true)) {
218       addSuper(supers, aClass);
219     }
220     else {
221       final PsiClass[] aSupers = aClass.getSupers();
222       for (PsiClass aSuper : aSupers) {
223         if (visited.add(aSuper)) {
224           getLeastUpperClassesInner(aSuper, bClass, supers, visited);
225         }
226       }
227     }
228   }
229
230   private static void addSuper(final Set<PsiClass> supers, final PsiClass classToAdd) {
231     for (Iterator<PsiClass> iterator = supers.iterator(); iterator.hasNext();) {
232       PsiClass superClass = iterator.next();
233       if (InheritanceUtil.isInheritorOrSelf(superClass, classToAdd, true)) return;
234       if (classToAdd.isInheritor(superClass, true)) iterator.remove();
235     }
236     
237     supers.add(classToAdd);
238   }
239
240   public static boolean isTypeArgumentsApplicable(final PsiTypeParameter[] typeParams,
241                                                   final PsiSubstitutor substitutor,
242                                                   final PsiElement context) {
243     return isTypeArgumentsApplicable(typeParams, substitutor, context, true);
244   }
245
246   public static boolean isTypeArgumentsApplicable(final PsiTypeParameter[] typeParams,
247                                                   final PsiSubstitutor substitutor,
248                                                   final PsiElement context,
249                                                   final boolean allowUncheckedConversion) {
250     return findTypeParameterWithBoundError(typeParams, substitutor, context, allowUncheckedConversion) == null;
251   }
252
253   public static Pair<PsiTypeParameter, PsiType> findTypeParameterWithBoundError(final PsiTypeParameter[] typeParams,
254                                                                                 final PsiSubstitutor substitutor,
255                                                                                 final PsiElement context,
256                                                                                 final boolean allowUncheckedConversion) {
257     for (PsiTypeParameter typeParameter : typeParams) {
258       PsiType boundError = findTypeParameterBoundError(typeParameter, typeParameter.getExtendsListTypes(),
259                                                        substitutor, context, allowUncheckedConversion);
260       if (boundError != null) {
261         return Pair.create(typeParameter, boundError);
262       }
263     }
264     return null;
265   }
266
267   public static PsiType findTypeParameterBoundError(PsiTypeParameter typeParameter,
268                                                     PsiType[] extendsTypes,
269                                                     PsiSubstitutor substitutor,
270                                                     PsiElement context,
271                                                     boolean allowUncheckedConversion) {
272     PsiType substituted = substitutor.substitute(typeParameter);
273     if (substituted == null) return null;
274     if (context != null) {
275       substituted = PsiUtil.captureToplevelWildcards(substituted, context);
276     }
277
278     if (substituted instanceof PsiWildcardType) {
279       if (((PsiWildcardType)substituted).isSuper()) {
280         return null;
281       }
282     }
283
284     for (PsiType type : extendsTypes) {
285       PsiType extendsType = substitutor.substitute(type);
286       if (extendsType != null && 
287           !TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
288         return extendsType;
289       }
290     }
291     return null;
292   }
293
294   public static boolean isFromExternalTypeLanguage(@NotNull PsiType type) {
295     return type.getInternalCanonicalText().equals(type.getCanonicalText());
296   }
297
298   @Contract("null -> null")
299   public static PsiType getVariableTypeByExpressionType(@Nullable PsiType type) {
300     return getVariableTypeByExpressionType(type, true);
301   }
302
303   @Contract("null, _ -> null")
304   public static PsiType getVariableTypeByExpressionType(@Nullable PsiType type, final boolean openCaptured) {
305     if (type == null) return null;
306     PsiClass refClass = PsiUtil.resolveClassInType(type);
307     if (refClass instanceof PsiAnonymousClass) {
308       type = ((PsiAnonymousClass)refClass).getBaseClassType();
309     }
310     PsiType deepComponentType = type.getDeepComponentType();
311     if (deepComponentType instanceof PsiCapturedWildcardType) {
312       type = PsiTypesUtil.createArrayType(((PsiCapturedWildcardType)deepComponentType).getUpperBound(),
313                                           type.getArrayDimensions());
314     }
315     PsiType transformed = type.accept(new PsiTypeVisitor<PsiType>() {
316       @Override
317       public PsiType visitArrayType(PsiArrayType arrayType) {
318         PsiType componentType = arrayType.getComponentType();
319         PsiType type = componentType.accept(this);
320         if (type == componentType) return arrayType;
321         if (type instanceof PsiWildcardType) {
322           type = ((PsiWildcardType)type).getBound();
323         }
324         return type != null ? type.createArrayType() : arrayType;
325       }
326
327       @Override
328       public PsiType visitType(PsiType type) {
329         return type;
330       }
331
332       @Override
333       public PsiType visitWildcardType(final PsiWildcardType wildcardType) {
334         final PsiType bound = wildcardType.getBound();
335         PsiManager manager = wildcardType.getManager();
336         if (bound != null) {
337
338           if (wildcardType.isSuper() && bound instanceof PsiIntersectionType) {
339             return PsiWildcardType.createUnbounded(manager);
340           }
341
342           final PsiType acceptedBound = bound.accept(this);
343           if (acceptedBound instanceof PsiWildcardType) {
344             if (((PsiWildcardType)acceptedBound).isExtends() != wildcardType.isExtends()) return PsiWildcardType.createUnbounded(manager);
345             return acceptedBound;
346           }
347           if (wildcardType.isExtends() && acceptedBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return PsiWildcardType.createUnbounded(manager);
348           if (acceptedBound.equals(bound)) return wildcardType;
349           return wildcardType.isExtends()
350                  ? PsiWildcardType.createExtends(manager, acceptedBound)
351                  : PsiWildcardType.createSuper(manager, acceptedBound);
352         }
353         return wildcardType;
354       }
355
356       @Override
357       public PsiType visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
358         return openCaptured ? capturedWildcardType.getWildcard().accept(this) : capturedWildcardType;
359       }
360
361       @Override
362       public PsiType visitClassType(PsiClassType classType) {
363         PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
364         PsiClass aClass = resolveResult.getElement();
365         if (aClass == null) return classType;
366         boolean toExtend = false;
367         PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
368         for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) {
369           PsiType typeArgument = resolveResult.getSubstitutor().substitute(typeParameter);
370           if (typeArgument instanceof PsiCapturedWildcardType) toExtend = true;
371           if (typeArgument instanceof PsiWildcardType && ((PsiWildcardType)typeArgument).getBound() instanceof PsiIntersectionType) {
372             toExtend = true;
373           }
374           PsiType toPut;
375           if (typeArgument == null) {
376             toPut = null;
377           }
378           else {
379             final PsiType accepted = typeArgument.accept(this);
380             if (typeArgument instanceof PsiIntersectionType && !(accepted instanceof PsiWildcardType)) {
381               toPut = PsiWildcardType.createExtends(typeParameter.getManager(), accepted);
382             }
383             else {
384               toPut = accepted;
385             }
386           }
387           LOG.assertTrue(toPut == null || toPut.isValid(), toPut);
388           substitutor = substitutor.put(typeParameter, toPut);
389         }
390         PsiAnnotation[] applicableAnnotations = classType.getApplicableAnnotations();
391         if (substitutor == PsiSubstitutor.EMPTY && !toExtend && applicableAnnotations.length == 0 && !(aClass instanceof PsiTypeParameter)) {
392           return classType;
393         }
394         PsiManager manager = aClass.getManager();
395         PsiType result = JavaPsiFacade.getElementFactory(manager.getProject())
396           .createType(aClass, substitutor, PsiUtil.getLanguageLevel(aClass))
397           .annotate(TypeAnnotationProvider.Static.create(applicableAnnotations));
398         if (toExtend) result = PsiWildcardType.createExtends(manager, result);
399         return result;
400       }
401     });
402
403     PsiType componentType = transformed != null ? transformed.getDeepComponentType() : null;
404     if (componentType instanceof PsiWildcardType) {
405       componentType = ((PsiWildcardType)componentType).getExtendsBound();
406       return PsiTypesUtil.createArrayType(componentType, transformed.getArrayDimensions());
407     }
408     if (transformed instanceof PsiEllipsisType) {
409       return ((PsiEllipsisType)transformed).toArrayType();
410     }
411
412     return transformed;
413   }
414
415   public static PsiSubstitutor substituteByParameterName(final PsiClass psiClass, final PsiSubstitutor parentSubstitutor) {
416
417     final Map<PsiTypeParameter, PsiType> substitutionMap = parentSubstitutor.getSubstitutionMap();
418     final List<PsiType> result = new ArrayList<>(substitutionMap.size());
419     for (PsiTypeParameter typeParameter : psiClass.getTypeParameters()) {
420       final String name = typeParameter.getName();
421       final PsiTypeParameter key = ContainerUtil.find(substitutionMap.keySet(), psiTypeParameter -> name.equals(psiTypeParameter.getName()));
422       if (key != null) {
423         result.add(substitutionMap.get(key));
424       }
425     }
426     return PsiSubstitutor.EMPTY.putAll(psiClass, result.toArray(PsiType.createArray(result.size())));
427   }
428
429   public static PsiType eliminateWildcards(PsiType type) {
430     return eliminateWildcards(type, true);
431   }
432
433   public static PsiType eliminateWildcards(PsiType type, final boolean eliminateInTypeArguments) {
434     return eliminateWildcards(type, eliminateInTypeArguments, !eliminateInTypeArguments);
435   }
436
437   public static PsiType eliminateWildcards(PsiType type,
438                                            final boolean eliminateInTypeArguments,
439                                            boolean eliminateCapturedWildcards) {
440     if (eliminateInTypeArguments && type instanceof PsiClassType) {
441       PsiClassType classType = (PsiClassType)type;
442       JavaResolveResult resolveResult = classType.resolveGenerics();
443       PsiClass aClass = (PsiClass)resolveResult.getElement();
444       if (aClass != null) {
445         PsiManager manager = aClass.getManager();
446         PsiTypeParameter[] typeParams = aClass.getTypeParameters();
447         Map<PsiTypeParameter, PsiType> map = new HashMap<>();
448         for (PsiTypeParameter typeParam : typeParams) {
449           PsiType substituted = resolveResult.getSubstitutor().substitute(typeParam);
450           if (substituted instanceof PsiWildcardType) {
451             substituted = ((PsiWildcardType)substituted).getBound();
452             if (substituted instanceof PsiCapturedWildcardType) {
453               substituted = ((PsiCapturedWildcardType)substituted).getWildcard().getBound();
454             }
455             if (substituted == null) substituted = TypeConversionUtil.typeParameterErasure(typeParam);
456           }
457           map.put(typeParam, substituted);
458         }
459
460         PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject());
461         PsiSubstitutor substitutor = factory.createSubstitutor(map);
462         type = factory.createType(aClass, substitutor);
463       }
464     }
465     else if (type instanceof PsiArrayType) {
466       return eliminateWildcards(((PsiArrayType)type).getComponentType(), false).createArrayType();
467     }
468     else if (type instanceof PsiWildcardType) {
469       final PsiType bound = ((PsiWildcardType)type).getBound();
470       return eliminateWildcards(bound != null ? bound : ((PsiWildcardType)type).getExtendsBound(), false);//object
471     }
472     else if (type instanceof PsiCapturedWildcardType && eliminateCapturedWildcards) {
473       return eliminateWildcards(((PsiCapturedWildcardType)type).getUpperBound(), false);
474     }
475     return type;
476   }
477
478   public static boolean checkNotInBounds(PsiType type, PsiType bound, PsiReferenceParameterList referenceParameterList) {
479     //4.10.2
480     //Given a generic type declaration C<F1,...,Fn> (n > 0), the direct supertypes of the parameterized type C<R1,...,Rn> where at least one of the Ri is a wildcard
481     //type argument, are the direct supertypes of the parameterized type C<X1,...,Xn> which is the result of applying capture conversion to C<R1,...,Rn>.
482     PsiType capturedType = PsiUtil.captureToplevelWildcards(type, referenceParameterList);
483     //allow unchecked conversions in method calls but not in type declaration
484     return checkNotInBounds(capturedType, bound, PsiTreeUtil.getParentOfType(referenceParameterList, PsiCallExpression.class) != null);
485   }
486
487   public static boolean checkNotInBounds(PsiType type, PsiType bound, boolean uncheckedConversionByDefault) {
488     if (type instanceof PsiClassType) {
489       return checkNotAssignable(bound, type, uncheckedConversionByDefault);
490     }
491     if (type instanceof PsiWildcardType) {
492       if (((PsiWildcardType)type).isExtends()) {
493         return checkExtendsWildcardCaptureFailure((PsiWildcardType)type, bound);
494       }
495       else if (((PsiWildcardType)type).isSuper()) {
496         final PsiType superBound = ((PsiWildcardType)type).getSuperBound();
497         if (PsiUtil.resolveClassInType(superBound) instanceof PsiTypeParameter) return TypesDistinctProver.provablyDistinct(type, bound);
498         return checkNotAssignable(bound, superBound, false);
499       }
500     }
501     else if (type instanceof PsiArrayType) {
502       return checkNotAssignable(bound, type, true);
503     }
504     else if (type instanceof PsiIntersectionType) {
505       for (PsiType psiType : ((PsiIntersectionType)type).getConjuncts()) {
506         if (!checkNotInBounds(psiType, bound, uncheckedConversionByDefault)) {
507           return false; 
508         }
509       }
510       return true;
511     }
512     return false;
513   }
514
515   //JLS 5.1.10
516   private static boolean checkExtendsWildcardCaptureFailure(PsiWildcardType type, PsiType bound) {
517     LOG.assertTrue(type.isExtends());
518     final PsiType extendsBound = type.getExtendsBound();
519     PsiType boundBound = bound;
520     if (bound instanceof PsiWildcardType) {
521       if (((PsiWildcardType)bound).isBounded()) {
522         boundBound = ((PsiWildcardType)bound).isSuper()
523                      ? ((PsiWildcardType)bound).getSuperBound()
524                      : ((PsiWildcardType)bound).getExtendsBound();
525       }
526       else {
527         return false;
528       }
529     }
530
531     final PsiClass extendsBoundClass = PsiUtil.resolveClassInClassTypeOnly(extendsBound);
532     final PsiClass boundBoundClass = PsiUtil.resolveClassInClassTypeOnly(boundBound);
533     if (boundBoundClass != null && extendsBoundClass != null && !boundBoundClass.isInterface() && !extendsBoundClass.isInterface()) {
534       return !InheritanceUtil.isInheritorOrSelf(boundBoundClass, extendsBoundClass, true) &&
535              !InheritanceUtil.isInheritorOrSelf(extendsBoundClass, boundBoundClass, true);
536     }
537
538     return !TypeConversionUtil.areTypesConvertible(boundBound, extendsBound) &&
539            !TypeConversionUtil.areTypesConvertible(extendsBound, boundBound);
540   }
541
542   private static boolean checkNotAssignable(final PsiType bound,
543                                             final PsiType type,
544                                             final boolean allowUncheckedConversion) {
545     if (bound instanceof PsiWildcardType) {
546       if (((PsiWildcardType)bound).isBounded()) {
547         final PsiType boundBound = ((PsiWildcardType)bound).isExtends()
548                                    ? ((PsiWildcardType)bound).getExtendsBound()
549                                    : ((PsiWildcardType)bound).getSuperBound();
550         return !TypeConversionUtil.isAssignable(boundBound, type, allowUncheckedConversion);
551       }
552       else {
553         return true;
554       }
555     }
556     else {
557       return !TypeConversionUtil.isAssignable(bound, type, allowUncheckedConversion);
558     }
559   }
560
561   @NotNull
562   public static PsiClassType getExpectedGenericType(PsiElement context,
563                                                     PsiClass aClass,
564                                                     PsiClassType expectedType) {
565     List<PsiType> arguments = getExpectedTypeArguments(context, aClass, Arrays.asList(aClass.getTypeParameters()), expectedType);
566     return JavaPsiFacade.getElementFactory(context.getProject()).createType(aClass, arguments.toArray(PsiType.EMPTY_ARRAY));
567   }
568
569   /**
570    * Tries to find the type parameters applied to a class which are compatible with expected supertype
571    *
572    * @param context      a context element
573    * @param aClass       a class which type parameters should be found
574    * @param typeParams   type parameters to substitute (a subset of all type parameters of a class)
575    * @param expectedType an expected supertype
576    * @return a list of type arguments which correspond to passed type parameters
577    */
578   @NotNull
579   public static List<PsiType> getExpectedTypeArguments(PsiElement context,
580                                                        PsiClass aClass,
581                                                        Iterable<? extends PsiTypeParameter> typeParams,
582                                                        PsiClassType expectedType) {
583     PsiClassType.ClassResolveResult resolve = expectedType.resolveGenerics();
584     PsiClass expectedClass = resolve.getElement();
585
586     if (!InheritanceUtil.isInheritorOrSelf(aClass, expectedClass, true)) {
587       return ContainerUtil.map(typeParams, p -> (PsiType)null);
588     }
589
590     PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(expectedClass, aClass, PsiSubstitutor.EMPTY);
591     assert substitutor != null;
592
593     return ContainerUtil.map(typeParams, p -> getExpectedTypeArg(context, resolve, substitutor, p));
594   }
595
596   @Nullable
597   private static PsiType getExpectedTypeArg(PsiElement context,
598                                             PsiClassType.ClassResolveResult expectedType,
599                                             PsiSubstitutor superClassSubstitutor, PsiTypeParameter typeParam) {
600     PsiClass expectedClass = expectedType.getElement();
601     assert expectedClass != null;
602     for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(expectedClass)) {
603       PsiType paramSubstitution = superClassSubstitutor.substitute(parameter);
604       PsiClass inheritorCandidateParameter = PsiUtil.resolveClassInType(paramSubstitution);
605       if (inheritorCandidateParameter instanceof PsiTypeParameter &&
606           ((PsiTypeParameter)inheritorCandidateParameter).getOwner() == typeParam.getOwner() &&
607           inheritorCandidateParameter != typeParam) {
608         continue;
609       }
610
611       PsiType argSubstitution = expectedType.getSubstitutor().substitute(parameter);
612       PsiType substitution = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper()
613         .getSubstitutionForTypeParameter(typeParam, paramSubstitution, argSubstitution, true, PsiUtil.getLanguageLevel(context));
614       if (substitution != null && substitution != PsiType.NULL) {
615         return substitution;
616       }
617     }
618     return null;
619   }
620
621   public static boolean isGenericReference(PsiJavaCodeReferenceElement referenceElement, PsiJavaCodeReferenceElement qualifierElement) {
622     final PsiReferenceParameterList qualifierParameterList = qualifierElement.getParameterList();
623     if (qualifierParameterList != null) {
624       final PsiTypeElement[] typeParameterElements = qualifierParameterList.getTypeParameterElements();
625       if (typeParameterElements.length > 0) {
626         return true;
627       }
628     }
629     final PsiReferenceParameterList parameterList = referenceElement.getParameterList();
630     if (parameterList != null) {
631       final PsiTypeElement[] typeParameterElements = parameterList.getTypeParameterElements();
632       if (typeParameterElements.length > 0) {
633         return true;
634       }
635     }
636     return false;
637   }
638 }