public void merge(final Binding b, final boolean removeObject) { for (final PsiTypeVariable var : b.getBoundVariables()) { final int index = var.getIndex(); if (myBindings.get(index) != null) { LOG.error("Oops... Binding conflict..."); } else { final PsiType type = b.apply(var); final PsiClassType javaLangObject = PsiType.getJavaLangObject( PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject)); if (removeObject && javaLangObject.equals(type)) { final HashSet<PsiTypeVariable> cluster = myFactory.getClusterOf(var.getIndex()); if (cluster != null) { for (final PsiTypeVariable war : cluster) { final PsiType wtype = b.apply(war); if (!javaLangObject.equals(wtype)) { myBindings.put(index, type); break; } } } } else { myBindings.put(index, type); } } } }
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 Binding rise(final PsiType x, final PsiType y, final HashSet<Constraint> constraints) { final Binding binding = balance( x, y, new Balancer() { public Binding varType(final PsiTypeVariable x, final PsiType y) { if (y instanceof Bottom || y instanceof PsiWildcardType) { return create(); } return create(x, y); } public Binding varVar(final PsiTypeVariable x, final PsiTypeVariable y) { final int xi = x.getIndex(); final int yi = y.getIndex(); if (xi < yi) { return create(x, y); } else if (yi < xi) { return create(y, x); } else { return create(); } } public Binding typeVar(final PsiType x, final PsiTypeVariable y) { if (x == null) return create(y, Bottom.BOTTOM); if (x instanceof PsiWildcardType) return create(); return create(y, x); } }, constraints); return binding != null ? binding.reduceRecursive() : null; }
public Binding riseWithWildcard( final PsiType x, final PsiType y, final HashSet<Constraint> constraints) { final Binding binding = balance( x, y, new Balancer() { public Binding varType(final PsiTypeVariable x, final PsiType y) { if (y instanceof Bottom) { return create(); } if (y == null || y instanceof PsiWildcardType) { return null; } final PsiTypeVariable var = myFactory.create(); final Binding binding = create(x, PsiWildcardType.createSuper(PsiManager.getInstance(myProject), var)); binding.addTypeVariable(var); constraints.add(new Subtype(var, y)); return binding; } public Binding varVar(final PsiTypeVariable x, final PsiTypeVariable y) { final int xi = x.getIndex(); final int yi = y.getIndex(); if (xi == yi) return create(); return create( y, PsiWildcardType.createExtends(PsiManager.getInstance(myProject), x)); /* if (xi < yi) { return create(x, y); } else if (yi < xi) { return create(y, x); } else { return create(); } */ } public Binding typeVar(final PsiType x, final PsiTypeVariable y) { if (x == null) { return create(y, Bottom.BOTTOM); } if (x instanceof PsiWildcardType) { return null; } final PsiTypeVariable var = myFactory.create(); final Binding binding = create( y, PsiWildcardType.createExtends(PsiManager.getInstance(myProject), var)); binding.addTypeVariable(var); constraints.add(new Subtype(x, var)); return binding; } }, constraints); return binding != null ? binding.reduceRecursive() : null; }
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 Binding compose(final Binding b) { LOG.assertTrue(b instanceof BindingImpl); final BindingImpl b1 = this; final BindingImpl b2 = (BindingImpl) b; final BindingImpl b3 = new BindingImpl(); for (PsiTypeVariable boundVariable : myBoundVariables) { final int i = boundVariable.getIndex(); final PsiType b1i = b1.myBindings.get(i); final PsiType b2i = b2.myBindings.get(i); final int flag = (b1i == null ? 0 : 1) + (b2i == null ? 0 : 2); switch (flag) { case 0: break; case 1: /* b1(i)\b2(i) */ { final PsiType type = b2.apply(b1i); if (type == null) { return null; } b3.myBindings.put(i, type); b3.myCyclic = type instanceof PsiTypeVariable; } break; case 2: /* b2(i)\b1(i) */ { final PsiType type = b1.apply(b2i); if (type == null) { return null; } b3.myBindings.put(i, type); b3.myCyclic = type instanceof PsiTypeVariable; } break; case 3: /* b2(i) \cap b1(i) */ { final Binding common = rise(b1i, b2i, null); if (common == null) { return null; } final PsiType type = common.apply(b1i); if (type == null) { return null; } if (type == null) { return null; } b3.myBindings.put(i, type); b3.myCyclic = type instanceof PsiTypeVariable; } } } return b3; }