@Nullable public static PsiType getLeastUpperBound( @NotNull PsiType type1, @NotNull PsiType type2, PsiManager manager) { if (type1 instanceof GrTupleType && type2 instanceof GrTupleType) { GrTupleType tuple1 = (GrTupleType) type1; GrTupleType tuple2 = (GrTupleType) type2; PsiType[] components1 = tuple1.getComponentTypes(); PsiType[] components2 = tuple2.getComponentTypes(); if (components1.length == 0) return genNewListBy(type2, manager); if (components2.length == 0) return genNewListBy(type1, manager); PsiType[] components3 = new PsiType[Math.min(components1.length, components2.length)]; for (int i = 0; i < components3.length; i++) { PsiType c1 = components1[i]; PsiType c2 = components2[i]; if (c1 == null || c2 == null) { components3[i] = null; } else { components3[i] = getLeastUpperBound(c1, c2, manager); } } return new GrTupleType( components3, JavaPsiFacade.getInstance(manager.getProject()), tuple1.getScope().intersectWith(tuple2.getResolveScope())); } else if (checkEmptyListAndList(type1, type2)) { return genNewListBy(type2, manager); } else if (checkEmptyListAndList(type2, type1)) { return genNewListBy(type1, manager); } else if (type1 instanceof GrMapType && type2 instanceof GrMapType) { return GrMapType.merge(((GrMapType) type1), ((GrMapType) type2)); } else if (checkEmptyMapAndMap(type1, type2)) { return genNewMapBy(type2, manager); } else if (checkEmptyMapAndMap(type2, type1)) { return genNewMapBy(type1, manager); } else if (type1 instanceof GrClosureType && type2 instanceof GrClosureType) { GrClosureType clType1 = (GrClosureType) type1; GrClosureType clType2 = (GrClosureType) type2; GrSignature signature1 = clType1.getSignature(); GrSignature signature2 = clType2.getSignature(); if (signature1 instanceof GrClosureSignature && signature2 instanceof GrClosureSignature) { if (((GrClosureSignature) signature1).getParameterCount() == ((GrClosureSignature) signature2).getParameterCount()) { final GrClosureSignature signature = GrClosureSignatureImpl.getLeastUpperBound( ((GrClosureSignature) signature1), ((GrClosureSignature) signature2), manager); if (signature != null) { GlobalSearchScope scope = clType1.getResolveScope().intersectWith(clType2.getResolveScope()); final LanguageLevel languageLevel = ComparatorUtil.max(clType1.getLanguageLevel(), clType2.getLanguageLevel()); return GrClosureType.create( signature, scope, JavaPsiFacade.getInstance(manager.getProject()), languageLevel, true); } } } } else if (GroovyCommonClassNames.GROOVY_LANG_GSTRING.equals(type1.getCanonicalText()) && CommonClassNames.JAVA_LANG_STRING.equals(type2.getInternalCanonicalText())) { return type2; } else if (GroovyCommonClassNames.GROOVY_LANG_GSTRING.equals(type2.getCanonicalText()) && CommonClassNames.JAVA_LANG_STRING.equals(type1.getInternalCanonicalText())) { return type1; } final PsiType result = getLeastUpperBoundForNumericType(type1, type2); if (result != null) return result; return GenericsUtil.getLeastUpperBound(type1, type2, manager); }