public static PsiSubstitutor composeSubstitutors(PsiSubstitutor s1, PsiSubstitutor s2) { final Map<PsiTypeParameter, PsiType> map = s1.getSubstitutionMap(); Map<PsiTypeParameter, PsiType> result = new THashMap<PsiTypeParameter, PsiType>(map.size()); for (PsiTypeParameter parameter : map.keySet()) { result.put(parameter, s2.substitute(map.get(parameter))); } final Map<PsiTypeParameter, PsiType> map2 = s2.getSubstitutionMap(); for (PsiTypeParameter parameter : map2.keySet()) { if (!result.containsKey(parameter)) { result.put(parameter, map2.get(parameter)); } } return PsiSubstitutorImpl.createSubstitutor(result); }
private static PsiSubstitutor obtainFinalSubstitutor( PsiClass superClass, PsiSubstitutor superSubstitutor, PsiSubstitutor derivedSubstitutor, boolean inRawContext) { if (inRawContext) { Set<PsiTypeParameter> typeParams = superSubstitutor.getSubstitutionMap().keySet(); PsiElementFactory factory = JavaPsiFacade.getElementFactory(superClass.getProject()); superSubstitutor = factory.createRawSubstitutor( derivedSubstitutor, typeParams.toArray(new PsiTypeParameter[typeParams.size()])); } Map<PsiTypeParameter, PsiType> map = null; for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) { PsiType type = superSubstitutor.substitute(typeParameter); final PsiType t = derivedSubstitutor.substitute(type); if (map == null) { map = new THashMap<PsiTypeParameter, PsiType>(); } map.put(typeParameter, t); } return map == null ? PsiSubstitutor.EMPTY : JavaPsiFacade.getInstance(superClass.getProject()) .getElementFactory() .createSubstitutor(map); }
private Binding unify(final PsiType x, final PsiType y, final Unifier unifier) { final int indicator = (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0); switch (indicator) { case 0: if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) { return unifier.unify(x, y); } else if (x instanceof PsiArrayType || y instanceof PsiArrayType) { final PsiType xType = x instanceof PsiArrayType ? ((PsiArrayType) x).getComponentType() : x; final PsiType yType = y instanceof PsiArrayType ? ((PsiArrayType) y).getComponentType() : y; return unify(xType, yType, unifier); } else if (x instanceof PsiClassType && y instanceof PsiClassType) { final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); final PsiClass xClass = resultX.getElement(); final PsiClass yClass = resultY.getElement(); if (xClass != null && yClass != null) { final PsiSubstitutor ySubst = resultY.getSubstitutor(); final PsiSubstitutor xSubst = resultX.getSubstitutor(); if (!xClass.equals(yClass)) { return null; } Binding b = create(); for (final PsiTypeParameter aParm : xSubst.getSubstitutionMap().keySet()) { final PsiType xType = xSubst.substitute(aParm); final PsiType yType = ySubst.substitute(aParm); final Binding b1 = unify(xType, yType, unifier); if (b1 == null) { return null; } b = b.compose(b1); } return b; } } else if (y instanceof Bottom) { return create(); } else { return null; } default: return unifier.unify(x, y); } }
public PsiType substitute(final PsiType t) { if (t instanceof PsiWildcardType) { final PsiWildcardType wcType = (PsiWildcardType) t; final PsiType bound = wcType.getBound(); if (bound == null) { return t; } final PsiManager manager = PsiManager.getInstance(myProject); final PsiType subst = substitute(bound); if (subst == null) return null; return subst instanceof PsiWildcardType ? subst : wcType.isExtends() ? PsiWildcardType.createExtends(manager, subst) : PsiWildcardType.createSuper(manager, subst); } else if (t instanceof PsiTypeVariable) { final PsiType b = apply(t); if (b instanceof Bottom || b instanceof PsiTypeVariable) { return null; } return substitute(b); } else if (t instanceof Bottom) { return null; } else if (t instanceof PsiArrayType) { return substitute(((PsiArrayType) t).getComponentType()).createArrayType(); } else if (t instanceof PsiClassType) { final PsiClassType.ClassResolveResult result = ((PsiClassType) t).resolveGenerics(); final PsiClass aClass = result.getElement(); final PsiSubstitutor aSubst = result.getSubstitutor(); if (aClass != null) { PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; for (final PsiTypeParameter parm : aSubst.getSubstitutionMap().keySet()) { final PsiType type = aSubst.substitute(parm); theSubst = theSubst.put(parm, substitute(type)); } return JavaPsiFacade.getInstance(aClass.getProject()) .getElementFactory() .createType(aClass, theSubst); } } return t; }
public PsiType apply(final PsiType type) { if (type instanceof PsiTypeVariable) { final PsiType t = myBindings.get(((PsiTypeVariable) type).getIndex()); return t == null ? type : t; } else if (type instanceof PsiArrayType) { return apply(((PsiArrayType) type).getComponentType()).createArrayType(); } else if (type instanceof PsiClassType) { final PsiClassType.ClassResolveResult result = Util.resolveType(type); final PsiClass theClass = result.getElement(); final PsiSubstitutor aSubst = result.getSubstitutor(); PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; if (theClass != null) { for (final PsiTypeParameter aParm : aSubst.getSubstitutionMap().keySet()) { final PsiType aType = aSubst.substitute(aParm); theSubst = theSubst.put(aParm, apply(aType)); } return JavaPsiFacade.getInstance(theClass.getProject()) .getElementFactory() .createType(theClass, theSubst); } else { return type; } } else if (type instanceof PsiWildcardType) { final PsiWildcardType wcType = (PsiWildcardType) type; final PsiType bound = wcType.getBound(); if (bound != null) { final PsiType abound = apply(bound); if (abound instanceof PsiWildcardType) { return null; } return wcType.isExtends() ? PsiWildcardType.createExtends(PsiManager.getInstance(myProject), abound) : PsiWildcardType.createSuper(PsiManager.getInstance(myProject), abound); } return type; } else { return type; } }
@NotNull private PsiSubstitutor mapSubstitutor( PsiClass originalClass, PsiClass mappedClass, PsiSubstitutor substitutor) { PsiTypeParameter[] typeParameters = mappedClass.getTypeParameters(); PsiTypeParameter[] originalTypeParameters = originalClass.getTypeParameters(); if (typeParameters.length != originalTypeParameters.length) { if (originalTypeParameters.length == 0) { return JavaPsiFacade.getElementFactory(mappedClass.getProject()) .createRawSubstitutor(mappedClass); } return substitutor; } Map<PsiTypeParameter, PsiType> substitutionMap = substitutor.getSubstitutionMap(); PsiSubstitutor mappedSubstitutor = PsiSubstitutor.EMPTY; for (int i = 0; i < originalTypeParameters.length; i++) { if (!substitutionMap.containsKey(originalTypeParameters[i])) continue; PsiType originalSubstitute = substitutor.substitute(originalTypeParameters[i]); if (originalSubstitute != null) { PsiType substitute = mapType(originalSubstitute); if (substitute == null) return substitutor; mappedSubstitutor = mappedSubstitutor.put(typeParameters[i], substitute); } else { mappedSubstitutor = mappedSubstitutor.put(typeParameters[i], null); } } if (mappedClass.hasModifierProperty(PsiModifier.STATIC)) { return mappedSubstitutor; } PsiClass mappedContaining = mappedClass.getContainingClass(); PsiClass originalContaining = originalClass.getContainingClass(); //noinspection DoubleNegation if ((mappedContaining != null) != (originalContaining != null)) { return substitutor; } if (mappedContaining != null) { return mappedSubstitutor.putAll( mapSubstitutor(originalContaining, mappedContaining, substitutor)); } return mappedSubstitutor; }
@NotNull private static PsiSubstitutor calculateMethodSubstitutor( @NotNull PsiTypeParameter[] typeParameters, @NotNull PsiMethod method, @NotNull PsiSubstitutor siteSubstitutor, @NotNull PsiType[] types1, @NotNull PsiType[] types2, @NotNull LanguageLevel languageLevel) { PsiSubstitutor substitutor = PsiResolveHelper.SERVICE .getInstance(method.getProject()) .inferTypeArguments(typeParameters, types1, types2, languageLevel); for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(method)) { ProgressManager.checkCanceled(); LOG.assertTrue(typeParameter != null); if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) { PsiType type = siteSubstitutor.substitute(typeParameter); if (type instanceof PsiClassType && typeParameter.getOwner() == method) { final PsiClass aClass = ((PsiClassType) type).resolve(); if (aClass instanceof PsiTypeParameter && ((PsiTypeParameter) aClass).getOwner() == method) { type = TypeConversionUtil.erasure(type, siteSubstitutor); } } substitutor = substitutor.put(typeParameter, type); } else { final PsiType type = substitutor.substitute(typeParameter); if (type instanceof PsiClassType) { final PsiClass aClass = ((PsiClassType) type).resolve(); if (aClass instanceof PsiTypeParameter) { substitutor = substitutor.put( typeParameter, JavaPsiFacade.getElementFactory(aClass.getProject()) .createType(aClass, siteSubstitutor)); } } } } return substitutor; }
public static PsiSubstitutor combineSubstitutors( PsiSubstitutor substitutor1, PsiSubstitutor substitutor2) { if (substitutor1 == PsiSubstitutor.EMPTY) return substitutor2; Set<PsiTypeParameter> parameters1 = substitutor1.getSubstitutionMap().keySet(); final PsiTypeParameter[] typeParameters = parameters1.toArray(new PsiTypeParameter[parameters1.size()]); for (PsiTypeParameter typeParameter : typeParameters) { final PsiType type = substitutor1.substitute(typeParameter); PsiType otherSubstituted; if (type instanceof PsiClassType) { final PsiClass resolved = ((PsiClassType) type).resolve(); otherSubstituted = resolved instanceof PsiTypeParameter ? substitutor2.substitute((PsiTypeParameter) resolved) : substitutor2.substitute(type); } else { otherSubstituted = substitutor2.substitute(type); } substitutor1 = substitutor1.put(typeParameter, otherSubstituted); } return substitutor1; }
private static boolean provablyDistinct(PsiType type1, PsiType type2, int level) { if (type1 instanceof PsiClassType && ((PsiClassType) type1).resolve() instanceof PsiTypeParameter) return false; if (type2 instanceof PsiClassType && ((PsiClassType) type2).resolve() instanceof PsiTypeParameter) return false; if (type1 instanceof PsiWildcardType) { if (type2 instanceof PsiWildcardType) { return provablyDistinct((PsiWildcardType) type1, (PsiWildcardType) type2); } if (type2 instanceof PsiCapturedWildcardType) { return ((PsiWildcardType) type1).isExtends() && level > 0 || provablyDistinct( (PsiWildcardType) type1, ((PsiCapturedWildcardType) type2).getWildcard()); } if (type2 instanceof PsiClassType) { final PsiClass psiClass2 = PsiUtil.resolveClassInType(type2); if (psiClass2 == null) return false; if (((PsiWildcardType) type1).isExtends()) { final PsiType extendsBound = ((PsiWildcardType) type1).getExtendsBound(); if (extendsBound instanceof PsiArrayType && proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) extendsBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound); if (boundClass1 == null) return false; return proveExtendsBoundsDistinct(type1, type2, boundClass1, psiClass2); } if (((PsiWildcardType) type1).isSuper()) { final PsiType superBound = ((PsiWildcardType) type1).getSuperBound(); if (superBound instanceof PsiArrayType && proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) superBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(superBound); if (boundClass1 == null || boundClass1 instanceof PsiTypeParameter) return false; return !InheritanceUtil.isInheritorOrSelf(boundClass1, psiClass2, true); } final PsiType bound = ((PsiWildcardType) type1).getBound(); return bound != null && !bound.equals(psiClass2); } if (type2 instanceof PsiArrayType) { return proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) type2, type1); } } if (type1 instanceof PsiCapturedWildcardType) return provablyDistinct(((PsiCapturedWildcardType) type1).getWildcard(), type2, level); if (type2 instanceof PsiWildcardType || type2 instanceof PsiCapturedWildcardType) return provablyDistinct(type2, type1, level); final PsiClassType.ClassResolveResult classResolveResult1 = PsiUtil.resolveGenericsClassInType(type1); final PsiClassType.ClassResolveResult classResolveResult2 = PsiUtil.resolveGenericsClassInType(type2); if (Comparing.equal(TypeConversionUtil.erasure(type1), TypeConversionUtil.erasure(type2))) { final PsiSubstitutor substitutor1 = classResolveResult1.getSubstitutor(); final PsiSubstitutor substitutor2 = classResolveResult2.getSubstitutor(); for (PsiTypeParameter parameter : substitutor1.getSubstitutionMap().keySet()) { final PsiType substitutedType1 = substitutor1.substitute(parameter); final PsiType substitutedType2 = substitutor2.substitute(parameter); if (substitutedType1 == null && substitutedType2 == null) return false; if (substitutedType1 == null || substitutedType2 == null) { return true; } else { if (provablyDistinct(substitutedType1, substitutedType2, level + 1)) return true; if (substitutedType1 instanceof PsiWildcardType && !((PsiWildcardType) substitutedType1).isBounded()) return true; } } return false; } final PsiClass boundClass1 = classResolveResult1.getElement(); final PsiClass boundClass2 = classResolveResult2.getElement(); return type2 != null && type1 != null && !type1.equals(type2) && (!InheritanceUtil.isInheritorOrSelf(boundClass1, boundClass2, true) || !InheritanceUtil.isInheritorOrSelf(boundClass2, boundClass1, true)); }
public Binding balance( final PsiType x, final PsiType y, final Balancer balancer, final HashSet<Constraint> constraints) { final int indicator = (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0); switch (indicator) { case 0: if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) { final PsiType xType = x instanceof PsiWildcardType ? ((PsiWildcardType) x).getBound() : x; final PsiType yType = y instanceof PsiWildcardType ? ((PsiWildcardType) y).getBound() : y; switch ((x instanceof PsiWildcardType ? 1 : 0) + (y instanceof PsiWildcardType ? 2 : 0)) { case 1: if (((PsiWildcardType) x).isExtends()) { /* ? extends T1, T2 */ return null; } else { /* ? super T1, T2 */ if (xType != null && !"java.lang.Object".equals(xType.getCanonicalText())) { return null; } return create(); } case 2: if (((PsiWildcardType) y).isExtends()) { /* T1, ? extends T2 */ if (yType instanceof PsiTypeVariable) { final PsiTypeVariable beta = myFactory.create(); if (constraints != null) { constraints.add(new Subtype(beta, yType)); if (x != null) { constraints.add(new Subtype(x, yType)); } } return create(); } else { if (constraints != null && xType != null && yType != null) { constraints.add(new Subtype(xType, yType)); } return balance(xType, yType, balancer, constraints); } } else { /* T1, ? super T2 */ if (yType instanceof PsiTypeVariable) { final PsiTypeVariable beta = myFactory.create(); if (constraints != null) { if (x != null) constraints.add(new Subtype(x, beta)); constraints.add(new Subtype(yType, beta)); } return create(); } else { if (constraints != null && yType != null && xType != null) { constraints.add(new Subtype(yType, xType)); } return balance(xType, yType, balancer, constraints); } } case 3: switch ((((PsiWildcardType) x).isExtends() ? 0 : 1) + (((PsiWildcardType) y).isExtends() ? 0 : 2)) { case 0: /* ? super T1, ? super T2 */ if (constraints != null && xType != null && yType != null) { constraints.add(new Subtype(yType, xType)); } return balance(xType, yType, balancer, constraints); case 1: /* ? extends T1, ? super T2 */ if (constraints != null && xType != null && yType != null) { constraints.add(new Subtype(xType, yType)); } return balance(xType, yType, balancer, constraints); case 2: /* ? super T1, ? extends T2*/ return null; case 3: /* ? extends T1, ? extends T2*/ if (constraints != null && xType != null && yType != null) { constraints.add(new Subtype(xType, yType)); } return balance(xType, yType, balancer, constraints); } } return create(); } else if (x instanceof PsiArrayType || y instanceof PsiArrayType) { final PsiType xType = x instanceof PsiArrayType ? ((PsiArrayType) x).getComponentType() : x; final PsiType yType = y instanceof PsiArrayType ? ((PsiArrayType) y).getComponentType() : y; return balance(xType, yType, balancer, constraints); } else if (x instanceof PsiClassType && y instanceof PsiClassType) { final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); final PsiClass xClass = resultX.getElement(); final PsiClass yClass = resultY.getElement(); if (xClass != null && yClass != null) { final PsiSubstitutor ySubst = resultY.getSubstitutor(); PsiSubstitutor xSubst = TypeConversionUtil.getClassSubstitutor(yClass, xClass, resultX.getSubstitutor()); if (xSubst == null) return null; Binding b = create(); for (final PsiTypeParameter aParm : xSubst.getSubstitutionMap().keySet()) { final PsiType xType = xSubst.substitute(aParm); final PsiType yType = ySubst.substitute(aParm); final Binding b1 = unify( xType, yType, new Unifier() { public Binding unify(final PsiType x, final PsiType y) { return balance(x, y, balancer, constraints); } }); if (b1 == null) { return null; } b = b.compose(b1); } return b; } } else if (y instanceof Bottom) { return create(); } else { return null; } break; case 1: return balancer.varType((PsiTypeVariable) x, y); case 2: return balancer.typeVar(x, (PsiTypeVariable) y); case 3: return balancer.varVar((PsiTypeVariable) x, (PsiTypeVariable) y); } return null; }
public void setupTypeElement( PsiTypeElement typeElement, ExpectedTypeInfo[] infos, PsiSubstitutor substitutor, TemplateBuilder builder, @Nullable PsiElement context, PsiClass targetClass) { LOG.assertTrue(typeElement.isValid()); ApplicationManager.getApplication().assertWriteAccessAllowed(); PsiManager manager = typeElement.getManager(); GlobalSearchScope scope = typeElement.getResolveScope(); Project project = manager.getProject(); if (infos.length == 1 && substitutor != null && substitutor != PsiSubstitutor.EMPTY) { ExpectedTypeInfo info = infos[0]; Map<PsiTypeParameter, PsiType> map = substitutor.getSubstitutionMap(); PsiType[] vals = map.values().toArray(PsiType.createArray(map.size())); PsiTypeParameter[] params = map.keySet().toArray(new PsiTypeParameter[map.size()]); List<PsiType> types = matchingTypeParameters(vals, params, info); if (!types.isEmpty()) { ContainerUtil.addAll( types, ExpectedTypesProvider.processExpectedTypes( infos, new MyTypeVisitor(manager, scope), project)); builder.replaceElement( typeElement, new TypeExpression(project, types.toArray(PsiType.createArray(types.size())))); return; } else { PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); PsiType type = info.getType(); PsiType defaultType = info.getDefaultType(); try { PsiTypeElement inplaceTypeElement = ((PsiVariable) factory.createVariableDeclarationStatement("foo", type, null) .getDeclaredElements()[0]) .getTypeElement(); PsiSubstitutor rawingSubstitutor = getRawingSubstitutor(context, targetClass); int substitionResult = substituteToTypeParameters( typeElement, inplaceTypeElement, vals, params, builder, rawingSubstitutor, true); if (substitionResult != SUBSTITUTED_NONE) { if (substitionResult == SUBSTITUTED_IN_PARAMETERS) { PsiJavaCodeReferenceElement refElement = typeElement.getInnermostComponentReferenceElement(); LOG.assertTrue(refElement != null && refElement.getReferenceNameElement() != null); type = getComponentType(type); LOG.assertTrue(type != null); defaultType = getComponentType(defaultType); LOG.assertTrue(defaultType != null); ExpectedTypeInfo info1 = ExpectedTypesProvider.createInfo( ((PsiClassType) defaultType).rawType(), ExpectedTypeInfo.TYPE_STRICTLY, ((PsiClassType) defaultType).rawType(), info.getTailType()); MyTypeVisitor visitor = new MyTypeVisitor(manager, scope); builder.replaceElement( refElement.getReferenceNameElement(), new TypeExpression( project, ExpectedTypesProvider.processExpectedTypes( new ExpectedTypeInfo[] {info1}, visitor, project))); } return; } } catch (IncorrectOperationException e) { LOG.error(e); } } } PsiType[] types = infos.length == 0 ? new PsiType[] {typeElement.getType()} : ExpectedTypesProvider.processExpectedTypes( infos, new MyTypeVisitor(manager, scope), project); builder.replaceElement(typeElement, new TypeExpression(project, types)); }