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;
}
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) };
}
}
}
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);
}
}
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;
}
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());
}
}
Aggregations