2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.refactoring
.typeCook
.deductive
.resolver
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.openapi
.util
.Pair
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.search
.GlobalSearchScope
;
23 import com
.intellij
.psi
.util
.PsiUtil
;
24 import com
.intellij
.psi
.util
.TypeConversionUtil
;
25 import com
.intellij
.refactoring
.typeCook
.Settings
;
26 import com
.intellij
.refactoring
.typeCook
.Util
;
27 import com
.intellij
.refactoring
.typeCook
.deductive
.PsiExtendedTypeVisitor
;
28 import com
.intellij
.refactoring
.typeCook
.deductive
.builder
.Constraint
;
29 import com
.intellij
.refactoring
.typeCook
.deductive
.builder
.ReductionSystem
;
30 import com
.intellij
.refactoring
.typeCook
.deductive
.builder
.Subtype
;
31 import com
.intellij
.util
.graph
.DFSTBuilder
;
32 import com
.intellij
.util
.graph
.Graph
;
33 import gnu
.trove
.TIntArrayList
;
34 import gnu
.trove
.TIntProcedure
;
35 import gnu
.trove
.TObjectIntHashMap
;
42 public class ResolverTree
{
43 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.typeCook.deductive.resolver.ResolverTree");
45 private ResolverTree
[] mySons
= new ResolverTree
[0];
46 private final BindingFactory myBindingFactory
;
47 private Binding myCurrentBinding
;
48 private final SolutionHolder mySolutions
;
49 private final Project myProject
;
50 private final TObjectIntHashMap
<PsiTypeVariable
> myBindingDegree
; //How many times this type variable is bound in the system
51 private final Settings mySettings
;
52 private boolean mySolutionFound
= false;
54 private HashSet
<Constraint
> myConstraints
;
56 public ResolverTree(final ReductionSystem system
) {
57 myBindingFactory
= new BindingFactory(system
);
58 mySolutions
= new SolutionHolder();
59 myCurrentBinding
= myBindingFactory
.create();
60 myConstraints
= system
.getConstraints();
61 myProject
= system
.getProject();
62 myBindingDegree
= calculateDegree();
63 mySettings
= system
.getSettings();
65 reduceCyclicVariables();
68 private ResolverTree(final ResolverTree parent
, final HashSet
<Constraint
> constraints
, final Binding binding
) {
69 myBindingFactory
= parent
.myBindingFactory
;
70 myCurrentBinding
= binding
;
71 mySolutions
= parent
.mySolutions
;
72 myConstraints
= constraints
;
73 myProject
= parent
.myProject
;
74 myBindingDegree
= calculateDegree();
75 mySettings
= parent
.mySettings
;
78 private static class PsiTypeVarCollector
extends PsiExtendedTypeVisitor
{
79 final HashSet
<PsiTypeVariable
> mySet
= new HashSet
<PsiTypeVariable
>();
81 public Object
visitTypeVariable(final PsiTypeVariable var
) {
87 public HashSet
<PsiTypeVariable
> getSet(final PsiType type
) {
93 private boolean isBoundElseWhere(final PsiTypeVariable var
) {
94 return myBindingDegree
.get(var
) != 1;
97 private boolean canBePruned(final Binding b
) {
98 if (mySettings
.exhaustive()) return false;
99 for (final PsiTypeVariable var
: b
.getBoundVariables()) {
100 final PsiType type
= b
.apply(var
);
102 if (!(type
instanceof PsiTypeVariable
) && isBoundElseWhere(var
)) {
110 private TObjectIntHashMap
<PsiTypeVariable
> calculateDegree() {
111 final TObjectIntHashMap
<PsiTypeVariable
> result
= new TObjectIntHashMap
<PsiTypeVariable
>();
113 for (final Constraint constr
: myConstraints
) {
114 final PsiTypeVarCollector collector
= new PsiTypeVarCollector();
116 setDegree(collector
.getSet(constr
.getRight()), result
);
122 private void setDegree(final HashSet
<PsiTypeVariable
> set
, TObjectIntHashMap
<PsiTypeVariable
> result
) {
123 for (final PsiTypeVariable var
: set
) {
124 result
.increment(var
);
128 private HashSet
<Constraint
> apply(final Binding b
) {
129 final HashSet
<Constraint
> result
= new HashSet
<Constraint
>();
131 for (final Constraint constr
: myConstraints
) {
132 result
.add(constr
.apply(b
));
138 private HashSet
<Constraint
> apply(final Binding b
, final HashSet
<Constraint
> additional
) {
139 final HashSet
<Constraint
> result
= new HashSet
<Constraint
>();
141 for (final Constraint constr
: myConstraints
) {
142 result
.add(constr
.apply(b
));
145 for (final Constraint constr
: additional
) {
146 result
.add(constr
.apply(b
));
152 private ResolverTree
applyRule(final Binding b
) {
153 final Binding newBinding
= b
!= null ? myCurrentBinding
.compose(b
) : null;
155 return newBinding
== null ?
null : new ResolverTree(this, apply(b
), newBinding
);
158 private ResolverTree
applyRule(final Binding b
, final HashSet
<Constraint
> additional
) {
159 final Binding newBinding
= b
!= null ? myCurrentBinding
.compose(b
) : null;
161 return newBinding
== null ?
null : new ResolverTree(this, apply(b
, additional
), newBinding
);
164 private void reduceCyclicVariables() {
165 final HashSet
<PsiTypeVariable
> nodes
= new HashSet
<PsiTypeVariable
>();
166 final HashSet
<Constraint
> candidates
= new HashSet
<Constraint
>();
168 final HashMap
<PsiTypeVariable
, HashSet
<PsiTypeVariable
>> ins
= new HashMap
<PsiTypeVariable
, HashSet
<PsiTypeVariable
>>();
169 final HashMap
<PsiTypeVariable
, HashSet
<PsiTypeVariable
>> outs
= new HashMap
<PsiTypeVariable
, HashSet
<PsiTypeVariable
>>();
171 for (final Constraint constraint
: myConstraints
) {
172 final PsiType left
= constraint
.getLeft();
173 final PsiType right
= constraint
.getRight();
175 if (left
instanceof PsiTypeVariable
&& right
instanceof PsiTypeVariable
) {
176 final PsiTypeVariable leftVar
= (PsiTypeVariable
)left
;
177 final PsiTypeVariable rightVar
= (PsiTypeVariable
)right
;
179 candidates
.add(constraint
);
184 final HashSet
<PsiTypeVariable
> in
= ins
.get(leftVar
);
185 final HashSet
<PsiTypeVariable
> out
= outs
.get(rightVar
);
188 final HashSet
<PsiTypeVariable
> newIn
= new HashSet
<PsiTypeVariable
>();
192 ins
.put(leftVar
, newIn
);
199 final HashSet
<PsiTypeVariable
> newOut
= new HashSet
<PsiTypeVariable
>();
203 outs
.put(rightVar
, newOut
);
211 final DFSTBuilder
<PsiTypeVariable
> dfstBuilder
= new DFSTBuilder
<PsiTypeVariable
>(new Graph
<PsiTypeVariable
>() {
212 public Collection
<PsiTypeVariable
> getNodes() {
216 public Iterator
<PsiTypeVariable
> getIn(final PsiTypeVariable n
) {
217 final HashSet
<PsiTypeVariable
> in
= ins
.get(n
);
220 return new HashSet
<PsiTypeVariable
>().iterator();
223 return in
.iterator();
226 public Iterator
<PsiTypeVariable
> getOut(final PsiTypeVariable n
) {
227 final HashSet
<PsiTypeVariable
> out
= outs
.get(n
);
230 return new HashSet
<PsiTypeVariable
>().iterator();
233 return out
.iterator();
238 final TIntArrayList sccs
= dfstBuilder
.getSCCs();
239 final HashMap
<PsiTypeVariable
, Integer
> index
= new HashMap
<PsiTypeVariable
, Integer
>();
241 sccs
.forEach(new TIntProcedure() {
244 public boolean execute(int size
) {
245 for (int j
= 0; j
< size
; j
++) {
246 index
.put(dfstBuilder
.getNodeByTNumber(myTNumber
+ j
), myTNumber
);
253 for (final Constraint constraint
: candidates
) {
254 if (index
.get(constraint
.getLeft()).equals(index
.get(constraint
.getRight()))) {
255 myConstraints
.remove(constraint
);
259 Binding binding
= myBindingFactory
.create();
261 for (final PsiTypeVariable fromVar
: index
.keySet()) {
262 final PsiTypeVariable toVar
= dfstBuilder
.getNodeByNNumber(index
.get(fromVar
).intValue());
264 if (!fromVar
.equals(toVar
)) {
265 binding
= binding
.compose(myBindingFactory
.create(fromVar
, toVar
));
267 if (binding
== null) {
273 if (binding
!= null && binding
.nonEmpty()) {
274 myCurrentBinding
= myCurrentBinding
.compose(binding
);
275 myConstraints
= apply(binding
);
279 private void reduceTypeType(final Constraint constr
) {
280 final PsiType left
= constr
.getLeft();
281 final PsiType right
= constr
.getRight();
282 final HashSet
<Constraint
> addendumRise
= new HashSet
<Constraint
>();
283 final HashSet
<Constraint
> addendumSink
= new HashSet
<Constraint
>();
284 final HashSet
<Constraint
> addendumWcrd
= new HashSet
<Constraint
>();
287 Binding riseBinding
= myBindingFactory
.rise(left
, right
, addendumRise
);
288 if (riseBinding
!= null) numSons
++;
289 Binding sinkBinding
= myBindingFactory
.sink(left
, right
, addendumSink
);
290 if (sinkBinding
!= null) numSons
++;
291 Binding wcrdBinding
= mySettings
.cookToWildcards() ? myBindingFactory
.riseWithWildcard(left
, right
, addendumWcrd
) : null;
292 if (wcrdBinding
!= null) numSons
++;
293 Binding omitBinding
= null;
295 if (mySettings
.exhaustive()) {
296 final PsiClassType
.ClassResolveResult rightResult
= Util
.resolveType(right
);
297 final PsiClassType
.ClassResolveResult leftResult
= Util
.resolveType(left
);
299 final PsiClass rightClass
= rightResult
.getElement();
300 final PsiClass leftClass
= leftResult
.getElement();
302 if (rightClass
!= null && leftClass
!= null && rightClass
.getManager().areElementsEquivalent(rightClass
, leftClass
)) {
303 if (PsiUtil
.typeParametersIterator(rightClass
).hasNext()) {
304 omitBinding
= myBindingFactory
.create();
306 for (PsiType type
: rightResult
.getSubstitutor().getSubstitutionMap().values()) {
307 if (! (type
instanceof Bottom
)) {
317 if (numSons
== 0) return;
319 if ((riseBinding
!= null && sinkBinding
!= null && riseBinding
.equals(sinkBinding
)) || canBePruned(riseBinding
)) {
324 if (riseBinding
!= null && wcrdBinding
!= null && riseBinding
.equals(wcrdBinding
)) {
329 myConstraints
.remove(constr
);
331 mySons
= new ResolverTree
[numSons
];
335 if (riseBinding
!= null) {
336 mySons
[n
++] = applyRule(riseBinding
, addendumRise
);
339 if (wcrdBinding
!= null) {
340 mySons
[n
++] = applyRule(wcrdBinding
, addendumWcrd
);
343 if (omitBinding
!= null) {
344 mySons
[n
++] = applyRule(omitBinding
, addendumWcrd
);
347 if (sinkBinding
!= null) {
348 mySons
[n
++] = applyRule(sinkBinding
, addendumSink
);
352 private void fillTypeRange(final PsiType lowerBound
,
353 final PsiType upperBound
,
354 final HashSet
<PsiType
> holder
) {
355 if (lowerBound
instanceof PsiClassType
&& upperBound
instanceof PsiClassType
) {
356 final PsiClassType
.ClassResolveResult resultLower
= ((PsiClassType
)lowerBound
).resolveGenerics();
357 final PsiClassType
.ClassResolveResult resultUpper
= ((PsiClassType
)upperBound
).resolveGenerics();
359 final PsiClass lowerClass
= resultLower
.getElement();
360 final PsiClass upperClass
= resultUpper
.getElement();
362 if (lowerClass
!= null && upperClass
!= null && !lowerClass
.equals(upperClass
)) {
363 final PsiSubstitutor upperSubst
= resultUpper
.getSubstitutor();
364 final PsiClass
[] parents
= upperClass
.getSupers();
365 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(myProject
).getElementFactory();
367 for (final PsiClass parent
: parents
) {
368 final PsiSubstitutor superSubstitutor
= TypeConversionUtil
.getClassSubstitutor(parent
, upperClass
, upperSubst
);
369 if (superSubstitutor
!= null) {
370 final PsiClassType type
= factory
.createType(parent
, superSubstitutor
);
372 fillTypeRange(lowerBound
, type
, holder
);
377 else if (lowerBound
instanceof PsiArrayType
&& upperBound
instanceof PsiArrayType
) {
378 fillTypeRange(((PsiArrayType
)lowerBound
).getComponentType(), ((PsiArrayType
)upperBound
).getComponentType(), holder
);
382 private PsiType
[] getTypeRange(final PsiType lowerBound
, final PsiType upperBound
) {
383 final HashSet
<PsiType
> range
= new HashSet
<PsiType
>();
385 range
.add(lowerBound
);
386 range
.add(upperBound
);
388 fillTypeRange(lowerBound
, upperBound
, range
);
390 return range
.toArray(new PsiType
[]{});
393 private void reduceInterval(final Constraint left
, final Constraint right
) {
394 final PsiType leftType
= left
.getLeft();
395 final PsiType rightType
= right
.getRight();
396 final PsiTypeVariable var
= (PsiTypeVariable
)left
.getRight();
398 if (leftType
.equals(rightType
)) {
399 final Binding binding
= myBindingFactory
.create(var
, leftType
);
401 myConstraints
.remove(left
);
402 myConstraints
.remove(right
);
404 mySons
= new ResolverTree
[]{applyRule(binding
)};
409 Binding riseBinding
= myBindingFactory
.rise(leftType
, rightType
, null);
410 Binding sinkBinding
= myBindingFactory
.sink(leftType
, rightType
, null);
412 int indicator
= (riseBinding
== null ?
0 : 1) + (sinkBinding
== null ?
0 : 1);
414 if (indicator
== 0) {
417 else if ((indicator
== 2 && riseBinding
.equals(sinkBinding
)) || canBePruned(riseBinding
)) {
422 PsiType
[] riseRange
= PsiType
.EMPTY_ARRAY
;
423 PsiType
[] sinkRange
= PsiType
.EMPTY_ARRAY
;
425 if (riseBinding
!= null) {
426 riseRange
= getTypeRange(riseBinding
.apply(rightType
), riseBinding
.apply(leftType
));
429 if (sinkBinding
!= null) {
430 sinkRange
= getTypeRange(sinkBinding
.apply(rightType
), sinkBinding
.apply(leftType
));
433 if (riseRange
.length
+ sinkRange
.length
> 0) {
434 myConstraints
.remove(left
);
435 myConstraints
.remove(right
);
438 mySons
= new ResolverTree
[riseRange
.length
+ sinkRange
.length
];
440 for (int i
= 0; i
< riseRange
.length
; i
++) {
441 final PsiType type
= riseRange
[i
];
443 mySons
[i
] = applyRule(riseBinding
.compose(myBindingFactory
.create(var
, type
)));
446 for (int i
= 0; i
< sinkRange
.length
; i
++) {
447 final PsiType type
= sinkRange
[i
];
449 mySons
[i
+ riseRange
.length
] = applyRule(sinkBinding
.compose(myBindingFactory
.create(var
, type
)));
453 private void reduce() {
454 if (myConstraints
.size() == 0) {
458 if (myCurrentBinding
.isCyclic()) {
459 reduceCyclicVariables();
462 final HashMap
<PsiTypeVariable
, Constraint
> myTypeVarConstraints
= new HashMap
<PsiTypeVariable
, Constraint
>();
463 final HashMap
<PsiTypeVariable
, Constraint
> myVarTypeConstraints
= new HashMap
<PsiTypeVariable
, Constraint
>();
465 for (final Constraint constr
: myConstraints
) {
466 final PsiType left
= constr
.getLeft();
467 final PsiType right
= constr
.getRight();
469 switch ((left
instanceof PsiTypeVariable ?
0 : 1) + (right
instanceof PsiTypeVariable ?
0 : 2)) {
475 final Constraint c
= myTypeVarConstraints
.get(right
);
478 final Constraint d
= myVarTypeConstraints
.get(right
);
481 reduceInterval(constr
, d
);
485 myTypeVarConstraints
.put((PsiTypeVariable
)right
, constr
);
488 reduceTypeVar(constr
, c
);
496 final Constraint c
= myVarTypeConstraints
.get(left
);
499 final Constraint d
= myTypeVarConstraints
.get(left
);
502 reduceInterval(d
, constr
);
506 myVarTypeConstraints
.put((PsiTypeVariable
)left
, constr
);
509 reduceVarType(constr
, c
);
516 reduceTypeType(constr
);
521 //T1 < a < b ... < T2
523 for (final Constraint constr
: myConstraints
) {
524 final PsiType left
= constr
.getLeft();
525 final PsiType right
= constr
.getRight();
527 if (!(left
instanceof PsiTypeVariable
) && right
instanceof PsiTypeVariable
) {
528 final HashSet
<PsiTypeVariable
> bound
= new PsiTypeVarCollector().getSet(left
);
530 if (bound
.contains(right
)) {
531 myConstraints
.remove(constr
);
532 mySons
= new ResolverTree
[]{applyRule(myBindingFactory
.create(((PsiTypeVariable
)right
), Bottom
.BOTTOM
))};
537 final PsiManager manager
= PsiManager
.getInstance(myProject
);
538 final PsiType leftType
= left
instanceof PsiWildcardType ?
((PsiWildcardType
)left
).getBound() : left
;
539 final PsiType
[] types
= getTypeRange(PsiType
.getJavaLangObject(manager
, GlobalSearchScope
.allScope(myProject
)), leftType
);
541 mySons
= new ResolverTree
[types
.length
];
543 if (types
.length
> 0) {
544 myConstraints
.remove(constr
);
547 for (int i
= 0; i
< types
.length
; i
++) {
548 final PsiType type
= types
[i
];
549 mySons
[i
] = applyRule(myBindingFactory
.create(((PsiTypeVariable
)right
), type
));
559 final HashSet
<PsiTypeVariable
> haveLeftBound
= new HashSet
<PsiTypeVariable
>();
561 Constraint target
= null;
562 final HashSet
<PsiTypeVariable
> boundVariables
= new HashSet
<PsiTypeVariable
>();
564 for (final Constraint constr
: myConstraints
) {
565 final PsiType leftType
= constr
.getLeft();
566 final PsiType rightType
= constr
.getRight();
568 if (leftType
instanceof PsiTypeVariable
) {
569 boundVariables
.add((PsiTypeVariable
)leftType
);
571 if (rightType
instanceof PsiTypeVariable
) {
572 boundVariables
.add((PsiTypeVariable
)rightType
);
573 haveLeftBound
.add(((PsiTypeVariable
)rightType
));
575 else if (!Util
.bindsTypeVariables(rightType
)) {
581 if (target
== null) {
582 if (mySettings
.exhaustive()) {
583 for (final Constraint constr
: myConstraints
) {
584 final PsiType left
= constr
.getLeft();
585 final PsiType right
= constr
.getRight();
587 PsiType
[] range
= null;
588 PsiTypeVariable var
= null;
590 if (left
instanceof PsiTypeVariable
&& !(right
instanceof PsiTypeVariable
)) {
591 range
= getTypeRange(PsiType
.getJavaLangObject(PsiManager
.getInstance(myProject
), GlobalSearchScope
.allScope(myProject
)),
593 var
= (PsiTypeVariable
)left
;
596 if (range
== null && right
instanceof PsiTypeVariable
&& !(left
instanceof PsiTypeVariable
)) {
597 range
= new PsiType
[]{right
};
598 var
= (PsiTypeVariable
)right
;
602 mySons
= new ResolverTree
[range
.length
];
604 for (int i
= 0; i
< range
.length
; i
++) {
605 mySons
[i
] = applyRule(myBindingFactory
.create(var
, range
[i
]));
613 Binding binding
= myBindingFactory
.create();
615 for (final PsiTypeVariable var
: myBindingFactory
.getBoundVariables()) {
616 if (!myCurrentBinding
.binds(var
) && !boundVariables
.contains(var
)) {
617 binding
= binding
.compose(myBindingFactory
.create(var
, Bottom
.BOTTOM
));
621 if (!binding
.nonEmpty()) {
622 myConstraints
.clear();
625 mySons
= new ResolverTree
[]{applyRule(binding
)};
628 final PsiType type
= target
.getRight();
629 final PsiTypeVariable var
= (PsiTypeVariable
)target
.getLeft();
631 final Binding binding
=
632 (haveLeftBound
.contains(var
) || type
instanceof PsiWildcardType
) || !mySettings
.cookToWildcards()
633 ? myBindingFactory
.create(var
, type
)
634 : myBindingFactory
.create(var
, PsiWildcardType
.createExtends(PsiManager
.getInstance(myProject
), type
));
636 myConstraints
.remove(target
);
638 mySons
= new ResolverTree
[]{applyRule(binding
)};
643 private void logSolution() {
644 LOG
.debug("Reduced system:");
646 for (final Constraint constr
: myConstraints
) {
647 LOG
.debug(constr
.toString());
650 LOG
.debug("End of Reduced system.");
651 LOG
.debug("Reduced binding:");
652 LOG
.debug(myCurrentBinding
.toString());
653 LOG
.debug("End of Reduced binding.");
656 private interface Reducer
{
657 LinkedList
<Pair
<PsiType
, Binding
>> unify(PsiType x
, PsiType y
);
659 Constraint
create(PsiTypeVariable var
, PsiType type
);
661 PsiType
getType(Constraint c
);
663 PsiTypeVariable
getVar(Constraint c
);
666 private void reduceTypeVar(final Constraint x
, final Constraint y
) {
667 reduceSideVar(x
, y
, new Reducer() {
668 public LinkedList
<Pair
<PsiType
, Binding
>> unify(final PsiType x
, final PsiType y
) {
669 return myBindingFactory
.intersect(x
, y
);
672 public Constraint
create(final PsiTypeVariable var
, final PsiType type
) {
673 return new Subtype(type
, var
);
676 public PsiType
getType(final Constraint c
) {
680 public PsiTypeVariable
getVar(final Constraint c
) {
681 return (PsiTypeVariable
)c
.getRight();
686 private void reduceVarType(final Constraint x
, final Constraint y
) {
687 reduceSideVar(x
, y
, new Reducer() {
688 public LinkedList
<Pair
<PsiType
, Binding
>> unify(final PsiType x
, final PsiType y
) {
689 return myBindingFactory
.union(x
, y
);
692 public Constraint
create(final PsiTypeVariable var
, final PsiType type
) {
693 return new Subtype(var
, type
);
696 public PsiType
getType(final Constraint c
) {
700 public PsiTypeVariable
getVar(final Constraint c
) {
701 return (PsiTypeVariable
)c
.getLeft();
706 private void reduceSideVar(final Constraint x
, final Constraint y
, final Reducer reducer
) {
707 final PsiTypeVariable var
= reducer
.getVar(x
);
709 final PsiType xType
= reducer
.getType(x
);
710 final PsiType yType
= reducer
.getType(y
);
712 final LinkedList
<Pair
<PsiType
, Binding
>> union
= reducer
.unify(xType
, yType
);
714 if (union
.size() == 0) {
718 myConstraints
.remove(x
);
719 myConstraints
.remove(y
);
721 mySons
= new ResolverTree
[union
.size()];
724 Constraint prev
= null;
726 for (final Pair
<PsiType
, Binding
> pair
: union
) {
728 myConstraints
.remove(prev
);
731 prev
= reducer
.create(var
, pair
.getFirst());
732 myConstraints
.add(prev
);
734 mySons
[i
++] = applyRule(pair
.getSecond());
738 public void resolve() {
741 if (mySons
.length
> 0) {
742 for (int i
= 0; i
< mySons
.length
; i
++) {
744 if (mySons
[i
] != null) {
746 if (!mySettings
.exhaustive() && mySettings
.cookToWildcards() && mySons
[i
].mySolutionFound
) break;
752 if (myConstraints
.size() == 0) {
755 mySolutions
.putSolution(myCurrentBinding
);
756 mySolutionFound
= true;
761 public Binding
getBestSolution() {
762 return mySolutions
.getBestSolution();