Search in sources :

Example 1 with Constraint

use of com.intellij.refactoring.typeCook.deductive.builder.Constraint in project intellij-community by JetBrains.

the class BindingFactory method balance.

public Binding balance(final PsiType x, final PsiType y, final Balancer balancer, final Set<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 && !CommonClassNames.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;
}
Also used : Constraint(com.intellij.refactoring.typeCook.deductive.builder.Constraint) Subtype(com.intellij.refactoring.typeCook.deductive.builder.Subtype)

Example 2 with Constraint

use of com.intellij.refactoring.typeCook.deductive.builder.Constraint in project intellij-community by JetBrains.

the class ResolverTree method reduce.

private void reduce() {
    if (myConstraints.isEmpty()) {
        return;
    }
    if (myCurrentBinding.isCyclic()) {
        reduceCyclicVariables();
    }
    final Map<PsiTypeVariable, Constraint> myTypeVarConstraints = new HashMap<>();
    final Map<PsiTypeVariable, Constraint> myVarTypeConstraints = new HashMap<>();
    for (final Constraint constr : myConstraints) {
        final PsiType left = constr.getLeft();
        final PsiType right = constr.getRight();
        switch((left instanceof PsiTypeVariable ? 0 : 1) + (right instanceof PsiTypeVariable ? 0 : 2)) {
            case 0:
                continue;
            case 1:
                {
                    final Constraint c = myTypeVarConstraints.get(right);
                    if (c == null) {
                        final Constraint d = myVarTypeConstraints.get(right);
                        if (d != null) {
                            reduceInterval(constr, d);
                            return;
                        }
                        myTypeVarConstraints.put((PsiTypeVariable) right, constr);
                    } else {
                        reduceTypeVar(constr, c);
                        return;
                    }
                }
                break;
            case 2:
                {
                    final Constraint c = myVarTypeConstraints.get(left);
                    if (c == null) {
                        final Constraint d = myTypeVarConstraints.get(left);
                        if (d != null) {
                            reduceInterval(d, constr);
                            return;
                        }
                        myVarTypeConstraints.put((PsiTypeVariable) left, constr);
                    } else {
                        reduceVarType(constr, c);
                        return;
                    }
                    break;
                }
            case 3:
                reduceTypeType(constr);
                return;
        }
    }
    //T1 < a < b ... < T2
    {
        for (final Constraint constr : myConstraints) {
            final PsiType left = constr.getLeft();
            final PsiType right = constr.getRight();
            if (!(left instanceof PsiTypeVariable) && right instanceof PsiTypeVariable) {
                Set<PsiTypeVariable> bound = new PsiTypeVarCollector().getSet(left);
                if (bound.contains(right)) {
                    myConstraints.remove(constr);
                    mySons = new ResolverTree[] { applyRule(myBindingFactory.create(((PsiTypeVariable) right), Bottom.BOTTOM)) };
                    return;
                }
                final PsiManager manager = PsiManager.getInstance(myProject);
                final PsiType leftType = left instanceof PsiWildcardType ? ((PsiWildcardType) left).getBound() : left;
                final PsiType[] types = getTypeRange(PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(myProject)), leftType);
                mySons = new ResolverTree[types.length];
                if (types.length > 0) {
                    myConstraints.remove(constr);
                }
                for (int i = 0; i < types.length; i++) {
                    final PsiType type = types[i];
                    mySons[i] = applyRule(myBindingFactory.create(((PsiTypeVariable) right), type));
                }
                return;
            }
        }
    }
    //T1 < a < b < ...
    {
        Set<PsiTypeVariable> haveLeftBound = new HashSet<>();
        Constraint target = null;
        Set<PsiTypeVariable> boundVariables = new HashSet<>();
        for (final Constraint constr : myConstraints) {
            final PsiType leftType = constr.getLeft();
            final PsiType rightType = constr.getRight();
            if (leftType instanceof PsiTypeVariable) {
                boundVariables.add((PsiTypeVariable) leftType);
                if (rightType instanceof PsiTypeVariable) {
                    boundVariables.add((PsiTypeVariable) rightType);
                    haveLeftBound.add(((PsiTypeVariable) rightType));
                } else if (!Util.bindsTypeVariables(rightType)) {
                    target = constr;
                }
            }
        }
        if (target == null) {
            if (mySettings.exhaustive()) {
                for (final Constraint constr : myConstraints) {
                    final PsiType left = constr.getLeft();
                    final PsiType right = constr.getRight();
                    PsiType[] range = null;
                    PsiTypeVariable var = null;
                    if (left instanceof PsiTypeVariable && !(right instanceof PsiTypeVariable)) {
                        range = getTypeRange(PsiType.getJavaLangObject(PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject)), right);
                        var = (PsiTypeVariable) left;
                    }
                    if (range == null && right instanceof PsiTypeVariable && !(left instanceof PsiTypeVariable)) {
                        range = new PsiType[] { right };
                        var = (PsiTypeVariable) right;
                    }
                    if (range != null) {
                        mySons = new ResolverTree[range.length];
                        for (int i = 0; i < range.length; i++) {
                            mySons[i] = applyRule(myBindingFactory.create(var, range[i]));
                        }
                        return;
                    }
                }
            }
            Binding binding = myBindingFactory.create();
            for (final PsiTypeVariable var : myBindingFactory.getBoundVariables()) {
                if (!myCurrentBinding.binds(var) && !boundVariables.contains(var)) {
                    binding = binding.compose(myBindingFactory.create(var, Bottom.BOTTOM));
                }
            }
            if (!binding.nonEmpty()) {
                myConstraints.clear();
            }
            mySons = new ResolverTree[] { applyRule(binding) };
        } else {
            final PsiType type = target.getRight();
            final PsiTypeVariable var = (PsiTypeVariable) target.getLeft();
            final Binding binding = (haveLeftBound.contains(var) || type instanceof PsiWildcardType) || !mySettings.cookToWildcards() ? myBindingFactory.create(var, type) : myBindingFactory.create(var, PsiWildcardType.createExtends(PsiManager.getInstance(myProject), type));
            myConstraints.remove(target);
            mySons = new ResolverTree[] { applyRule(binding) };
        }
    }
}
Also used : TObjectIntHashMap(gnu.trove.TObjectIntHashMap) Constraint(com.intellij.refactoring.typeCook.deductive.builder.Constraint)

Example 3 with Constraint

use of com.intellij.refactoring.typeCook.deductive.builder.Constraint in project intellij-community by JetBrains.

the class ResolverTree method reduceCyclicVariables.

private void reduceCyclicVariables() {
    final Set<PsiTypeVariable> nodes = new HashSet<>();
    final Set<Constraint> candidates = new HashSet<>();
    final Map<PsiTypeVariable, Set<PsiTypeVariable>> ins = new HashMap<>();
    final Map<PsiTypeVariable, Set<PsiTypeVariable>> outs = new HashMap<>();
    for (final Constraint constraint : myConstraints) {
        final PsiType left = constraint.getLeft();
        final PsiType right = constraint.getRight();
        if (left instanceof PsiTypeVariable && right instanceof PsiTypeVariable) {
            final PsiTypeVariable leftVar = (PsiTypeVariable) left;
            final PsiTypeVariable rightVar = (PsiTypeVariable) right;
            candidates.add(constraint);
            nodes.add(leftVar);
            nodes.add(rightVar);
            Set<PsiTypeVariable> in = ins.get(leftVar);
            Set<PsiTypeVariable> out = outs.get(rightVar);
            if (in == null) {
                final Set<PsiTypeVariable> newIn = new HashSet<>();
                newIn.add(rightVar);
                ins.put(leftVar, newIn);
            } else {
                in.add(rightVar);
            }
            if (out == null) {
                final Set<PsiTypeVariable> newOut = new HashSet<>();
                newOut.add(leftVar);
                outs.put(rightVar, newOut);
            } else {
                out.add(leftVar);
            }
        }
    }
    final DFSTBuilder<PsiTypeVariable> dfstBuilder = new DFSTBuilder<>(new Graph<PsiTypeVariable>() {

        @Override
        public Collection<PsiTypeVariable> getNodes() {
            return nodes;
        }

        @Override
        public Iterator<PsiTypeVariable> getIn(final PsiTypeVariable n) {
            final Set<PsiTypeVariable> in = ins.get(n);
            if (in == null) {
                return EmptyIterator.getInstance();
            }
            return in.iterator();
        }

        @Override
        public Iterator<PsiTypeVariable> getOut(final PsiTypeVariable n) {
            final Set<PsiTypeVariable> out = outs.get(n);
            if (out == null) {
                return EmptyIterator.getInstance();
            }
            return out.iterator();
        }
    });
    final TIntArrayList sccs = dfstBuilder.getSCCs();
    final Map<PsiTypeVariable, Integer> index = new HashMap<>();
    sccs.forEach(new TIntProcedure() {

        int myTNumber;

        @Override
        public boolean execute(int size) {
            for (int j = 0; j < size; j++) {
                index.put(dfstBuilder.getNodeByTNumber(myTNumber + j), myTNumber);
            }
            myTNumber += size;
            return true;
        }
    });
    for (final Constraint constraint : candidates) {
        if (index.get(constraint.getLeft()).equals(index.get(constraint.getRight()))) {
            myConstraints.remove(constraint);
        }
    }
    Binding binding = myBindingFactory.create();
    for (final PsiTypeVariable fromVar : index.keySet()) {
        final PsiTypeVariable toVar = dfstBuilder.getNodeByNNumber(index.get(fromVar).intValue());
        if (!fromVar.equals(toVar)) {
            binding = binding.compose(myBindingFactory.create(fromVar, toVar));
            if (binding == null) {
                break;
            }
        }
    }
    if (binding != null && binding.nonEmpty()) {
        myCurrentBinding = myCurrentBinding.compose(binding);
        myConstraints = apply(binding);
    }
}
Also used : TIntProcedure(gnu.trove.TIntProcedure) Constraint(com.intellij.refactoring.typeCook.deductive.builder.Constraint) TObjectIntHashMap(gnu.trove.TObjectIntHashMap) TIntArrayList(gnu.trove.TIntArrayList) Constraint(com.intellij.refactoring.typeCook.deductive.builder.Constraint) EmptyIterator(com.intellij.util.containers.EmptyIterator) DFSTBuilder(com.intellij.util.graph.DFSTBuilder)

Example 4 with Constraint

use of com.intellij.refactoring.typeCook.deductive.builder.Constraint in project intellij-community by JetBrains.

the class ResolverTree method calculateDegree.

private TObjectIntHashMap<PsiTypeVariable> calculateDegree() {
    final TObjectIntHashMap<PsiTypeVariable> result = new TObjectIntHashMap<>();
    for (final Constraint constr : myConstraints) {
        final PsiTypeVarCollector collector = new PsiTypeVarCollector();
        setDegree(collector.getSet(constr.getRight()), result);
    }
    return result;
}
Also used : TObjectIntHashMap(gnu.trove.TObjectIntHashMap) Constraint(com.intellij.refactoring.typeCook.deductive.builder.Constraint)

Example 5 with Constraint

use of com.intellij.refactoring.typeCook.deductive.builder.Constraint in project intellij-community by JetBrains.

the class ResolverTree method reduceSideVar.

private void reduceSideVar(final Constraint x, final Constraint y, final Reducer reducer) {
    final PsiTypeVariable var = reducer.getVar(x);
    final PsiType xType = reducer.getType(x);
    final PsiType yType = reducer.getType(y);
    final LinkedList<Pair<PsiType, Binding>> union = reducer.unify(xType, yType);
    if (union.isEmpty()) {
        return;
    }
    myConstraints.remove(x);
    myConstraints.remove(y);
    mySons = new ResolverTree[union.size()];
    int i = 0;
    Constraint prev = null;
    for (final Pair<PsiType, Binding> pair : union) {
        if (prev != null) {
            myConstraints.remove(prev);
        }
        prev = reducer.create(var, pair.getFirst());
        myConstraints.add(prev);
        mySons[i++] = applyRule(pair.getSecond());
    }
}
Also used : Constraint(com.intellij.refactoring.typeCook.deductive.builder.Constraint) Constraint(com.intellij.refactoring.typeCook.deductive.builder.Constraint) Pair(com.intellij.openapi.util.Pair)

Aggregations

Constraint (com.intellij.refactoring.typeCook.deductive.builder.Constraint)8 TObjectIntHashMap (gnu.trove.TObjectIntHashMap)3 Pair (com.intellij.openapi.util.Pair)1 Subtype (com.intellij.refactoring.typeCook.deductive.builder.Subtype)1 EmptyIterator (com.intellij.util.containers.EmptyIterator)1 DFSTBuilder (com.intellij.util.graph.DFSTBuilder)1 TIntArrayList (gnu.trove.TIntArrayList)1 TIntProcedure (gnu.trove.TIntProcedure)1