1package com.github.javaparser.symbolsolver.resolution.typeinference; 2 3import com.github.javaparser.resolution.types.ResolvedReferenceType; 4import com.github.javaparser.resolution.types.ResolvedType; 5import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 6import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; 7import com.github.javaparser.symbolsolver.resolution.typeinference.bounds.*; 8import com.github.javaparser.symbolsolver.resolution.typeinference.constraintformulas.TypeSameAsType; 9import com.github.javaparser.symbolsolver.resolution.typeinference.constraintformulas.TypeSubtypeOfType; 10import com.github.javaparser.utils.Pair; 11 12import java.util.*; 13import java.util.function.Predicate; 14import java.util.stream.Collectors; 15 16import static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.*; 17 18/** 19 * @author Federico Tomassetti 20 */ 21public class BoundSet { 22 23 private List<Bound> bounds = new LinkedList<>(); 24 25 private static final BoundSet EMPTY = new BoundSet(); 26 27 @Override 28 public boolean equals(Object o) { 29 if (this == o) return true; 30 if (o == null || getClass() != o.getClass()) return false; 31 32 BoundSet boundSet = (BoundSet) o; 33 34 return new HashSet<>(bounds).equals(new HashSet<>(boundSet.bounds)); 35 } 36 37 @Override 38 public int hashCode() { 39 return bounds.hashCode(); 40 } 41 42 @Override 43 public String toString() { 44 return "BoundSet{" + 45 "bounds=" + bounds + 46 '}'; 47 } 48 49 /** 50 51 * It is sometimes convenient to refer to an empty bound set with the symbol true; this is merely out of 52 * convenience, and the two are interchangeable. 53 */ 54 public boolean isTrue() { 55 return bounds.isEmpty(); 56 } 57 58 public static BoundSet empty() { 59 return EMPTY; 60 } 61 62 public BoundSet withBound(Bound bound) { 63 if (this.bounds.contains(bound)) { 64 return this; 65 } 66 BoundSet boundSet = new BoundSet(); 67 boundSet.bounds.addAll(this.bounds); 68 boundSet.bounds.add(bound); 69 return boundSet; 70 } 71 72 private Optional<Pair<SameAsBound, SameAsBound>> findPairSameAs(Predicate<Pair<SameAsBound, SameAsBound>> condition) { 73 for (int i=0;i<bounds.size();i++) { 74 Bound bi = bounds.get(i); 75 if (bi instanceof SameAsBound) { 76 SameAsBound si = (SameAsBound)bi; 77 for (int j = i + 1; j < bounds.size(); j++) { 78 Bound bj = bounds.get(j); 79 if (bj instanceof SameAsBound) { 80 SameAsBound sj = (SameAsBound)bj; 81 Pair<SameAsBound, SameAsBound> pair = new Pair<SameAsBound, SameAsBound>(si, sj); 82 if (condition.test(pair)) { 83 return Optional.of(pair); 84 } 85 } 86 } 87 } 88 } 89 return Optional.empty(); 90 } 91 92 public boolean isEmpty() { 93 return bounds.isEmpty(); 94 } 95 96 interface Processor<B1 extends Bound, B2 extends Bound, R> { 97 R process(B1 a, B2 b, R initialValue); 98 } 99 100 private <T> T forEachPairSameAs(Processor<SameAsBound, SameAsBound, T> processor, T initialValue) { 101 T currentValue = initialValue; 102 for (int i=0;i<bounds.size();i++) { 103 Bound bi = bounds.get(i); 104 if (bi instanceof SameAsBound) { 105 SameAsBound si = (SameAsBound)bi; 106 for (int j = i + 1; j < bounds.size(); j++) { 107 Bound bj = bounds.get(j); 108 if (bj instanceof SameAsBound) { 109 SameAsBound sj = (SameAsBound)bj; 110 currentValue = processor.process(si, sj, currentValue); 111 } 112 } 113 } 114 } 115 return currentValue; 116 } 117 118 private <T> T forEachPairSameAndSubtype(Processor<SameAsBound, SubtypeOfBound, T> processor, T initialValue) { 119 T currentValue = initialValue; 120 for (int i=0;i<bounds.size();i++) { 121 Bound bi = bounds.get(i); 122 if (bi instanceof SameAsBound) { 123 SameAsBound si = (SameAsBound)bi; 124 for (int j = i + 1; j < bounds.size(); j++) { 125 Bound bj = bounds.get(j); 126 if (bj instanceof SubtypeOfBound) { 127 SubtypeOfBound sj = (SubtypeOfBound)bj; 128 currentValue = processor.process(si, sj, currentValue); 129 } 130 } 131 } 132 } 133 return currentValue; 134 } 135 136 private <T> T forEachPairSubtypeAndSubtype(Processor<SubtypeOfBound, SubtypeOfBound, T> processor, T initialValue) { 137 T currentValue = initialValue; 138 for (int i=0;i<bounds.size();i++) { 139 Bound bi = bounds.get(i); 140 if (bi instanceof SubtypeOfBound) { 141 SubtypeOfBound si = (SubtypeOfBound)bi; 142 for (int j = i + 1; j < bounds.size(); j++) { 143 Bound bj = bounds.get(j); 144 if (bj instanceof SubtypeOfBound) { 145 SubtypeOfBound sj = (SubtypeOfBound)bj; 146 currentValue = processor.process(si, sj, currentValue); 147 } 148 } 149 } 150 } 151 return currentValue; 152 } 153 154 private boolean areSameTypeInference(ResolvedType a, ResolvedType b) { 155 return isInferenceVariable(a) && isInferenceVariable(b) && a.equals(b); 156 } 157 158 private List<Pair<ResolvedReferenceType, ResolvedReferenceType>> findPairsOfCommonAncestors(ResolvedReferenceType r1, ResolvedReferenceType r2) { 159 List<ResolvedReferenceType> set1 = new LinkedList<>(); 160 set1.add(r1); 161 set1.addAll(r1.getAllAncestors()); 162 List<ResolvedReferenceType> set2 = new LinkedList<>(); 163 set2.add(r2); 164 set2.addAll(r2.getAllAncestors()); 165 List<Pair<ResolvedReferenceType, ResolvedReferenceType>> pairs = new LinkedList<>(); 166 for (ResolvedReferenceType rtFrom1 : set1) { 167 for (ResolvedReferenceType rtFrom2 : set2) { 168 if (rtFrom1.getTypeDeclaration().equals(rtFrom2.getTypeDeclaration())) { 169 pairs.add(new Pair<>(rtFrom1, rtFrom2)); 170 } 171 } 172 } 173 return pairs; 174 } 175 176 /** 177 * Maintains a set of inference variable bounds, ensuring that these are consistent as new bounds are added. 178 * Because the bounds on one variable can sometimes impact the possible choices for another variable, this process 179 * propagates bounds between such interdependent variables. 180 */ 181 public BoundSet incorporate(BoundSet otherBounds, TypeSolver typeSolver) { 182 BoundSet newBoundSet = this; 183 for (Bound b : otherBounds.bounds) { 184 newBoundSet = newBoundSet.withBound(b); 185 } 186 return newBoundSet.deriveImpliedBounds(typeSolver); 187 } 188 189 public BoundSet deriveImpliedBounds(TypeSolver typeSolver) { 190 // As bound sets are constructed and grown during inference, it is possible that new bounds can be inferred 191 // based on the assertions of the original bounds. The process of incorporation identifies these new bounds 192 // and adds them to the bound set. 193 // 194 // Incorporation can happen in two scenarios. One scenario is that the bound set contains complementary pairs 195 // of bounds; this implies new constraint formulas, as specified in §18.3.1. The other scenario is that the 196 // bound set contains a bound involving capture conversion; this implies new bounds and may imply new 197 // constraint formulas, as specified in §18.3.2. In both scenarios, any new constraint formulas are reduced, 198 // and any new bounds are added to the bound set. This may trigger further incorporation; ultimately, the set 199 // will reach a fixed point and no further bounds can be inferred. 200 // 201 // If incorporation of a bound set has reached a fixed point, and the set does not contain the bound false, 202 // then the bound set has the following properties: 203 // 204 // - For each combination of a proper lower bound L and a proper upper bound U of an inference variable, L <: U. 205 // 206 // - If every inference variable mentioned by a bound has an instantiation, the bound is satisfied by the 207 // corresponding substitution. 208 // 209 // - Given a dependency α = β, every bound of α matches a bound of β, and vice versa. 210 // 211 // - Given a dependency α <: β, every lower bound of α is a lower bound of β, and every upper bound of β is an 212 // upper bound of α. 213 214 ConstraintFormulaSet newConstraintsSet = ConstraintFormulaSet.empty(); 215 216 // SECTION Complementary Pairs of Bounds 217 // (In this section, S and T are inference variables or types, and U is a proper type. For conciseness, a bound 218 // of the form α = T may also match a bound of the form T = α.) 219 // 220 // When a bound set contains a pair of bounds that match one of the following rules, a new constraint formula 221 // is implied: 222 // 223 // - α = S and α = T imply ‹S = T› 224 225 newConstraintsSet = forEachPairSameAs((a, b, currentConstraintSet) -> { 226 if (areSameTypeInference(a.getS(), b.getS())) { 227 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(a.getT(), b.getT())); 228 } 229 if (areSameTypeInference(a.getS(), b.getT())) { 230 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(a.getS(), b.getT())); 231 } 232 if (areSameTypeInference(a.getT(), b.getS())) { 233 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(a.getT(), b.getS())); 234 } 235 if (areSameTypeInference(a.getT(), b.getT())) { 236 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(a.getS(), b.getS())); 237 } 238 return currentConstraintSet; 239 }, newConstraintsSet); 240 241 // - α = S and α <: T imply ‹S <: T› 242 243 newConstraintsSet = forEachPairSameAndSubtype((a, b, currentConstraintSet) -> { 244 if (areSameTypeInference(a.getS(), b.getS())) { 245 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSubtypeOfType(typeSolver, a.getT(), b.getT())); 246 } 247 if (areSameTypeInference(a.getT(), b.getS())) { 248 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSubtypeOfType(typeSolver, a.getS(), b.getT())); 249 } 250 return currentConstraintSet; 251 }, newConstraintsSet); 252 253 // - α = S and T <: α imply ‹T <: S› 254 255 newConstraintsSet = forEachPairSameAndSubtype((a, b, currentConstraintSet) -> { 256 if (areSameTypeInference(a.getS(), b.getT())) { 257 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSubtypeOfType(typeSolver, b.getS(), a.getT())); 258 } 259 if (areSameTypeInference(a.getT(), b.getT())) { 260 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSubtypeOfType(typeSolver, b.getS(), a.getS())); 261 } 262 return currentConstraintSet; 263 }, newConstraintsSet); 264 265 // - S <: α and α <: T imply ‹S <: T› 266 267 newConstraintsSet = forEachPairSubtypeAndSubtype((a, b, currentConstraintSet) -> { 268 if (areSameTypeInference(a.getT(), b.getS())) { 269 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSubtypeOfType(typeSolver, b.getS(), a.getT())); 270 } 271 return currentConstraintSet; 272 }, newConstraintsSet); 273 274 // - α = U and S = T imply ‹S[α:=U] = T[α:=U]› 275 276 newConstraintsSet = forEachPairSameAs((a, b, currentConstraintSet) -> { 277 if (isInferenceVariable(a.getS()) && isProperType(a.getT())) { 278 InferenceVariable alpha = (InferenceVariable)a.getS(); 279 ResolvedType U = a.getT(); 280 ResolvedType S = b.getS(); 281 ResolvedType T = b.getT(); 282 Substitution sub = Substitution.empty().withPair(alpha.getTypeParameterDeclaration(), U); 283 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(sub.apply(S), sub.apply(T))); 284 } 285 if (isInferenceVariable(a.getT()) && isProperType(a.getS())) { 286 InferenceVariable alpha = (InferenceVariable)a.getT(); 287 ResolvedType U = a.getS(); 288 ResolvedType S = b.getS(); 289 ResolvedType T = b.getT(); 290 Substitution sub = Substitution.empty().withPair(alpha.getTypeParameterDeclaration(), U); 291 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(sub.apply(S), sub.apply(T))); 292 } 293 if (isInferenceVariable(b.getS()) && isProperType(b.getT())) { 294 InferenceVariable alpha = (InferenceVariable)b.getS(); 295 ResolvedType U = b.getT(); 296 ResolvedType S = a.getS(); 297 ResolvedType T = a.getT(); 298 Substitution sub = Substitution.empty().withPair(alpha.getTypeParameterDeclaration(), U); 299 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(sub.apply(S), sub.apply(T))); 300 } 301 if (isInferenceVariable(b.getT()) && isProperType(b.getS())) { 302 InferenceVariable alpha = (InferenceVariable)b.getT(); 303 ResolvedType U = b.getS(); 304 ResolvedType S = a.getS(); 305 ResolvedType T = a.getT(); 306 Substitution sub = Substitution.empty().withPair(alpha.getTypeParameterDeclaration(), U); 307 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(sub.apply(S), sub.apply(T))); 308 } 309 return currentConstraintSet; 310 }, newConstraintsSet); 311 312 // - α = U and S <: T imply ‹S[α:=U] <: T[α:=U]› 313 314 newConstraintsSet = forEachPairSameAndSubtype((a, b, currentConstraintSet) -> { 315 if (isInferenceVariable(a.getS()) && isProperType(a.getT())) { 316 InferenceVariable alpha = (InferenceVariable)a.getS(); 317 ResolvedType U = a.getT(); 318 ResolvedType S = b.getS(); 319 ResolvedType T = b.getT(); 320 Substitution sub = Substitution.empty().withPair(alpha.getTypeParameterDeclaration(), U); 321 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSubtypeOfType(typeSolver, sub.apply(S), sub.apply(T))); 322 } 323 if (isInferenceVariable(a.getT()) && isProperType(a.getS())) { 324 InferenceVariable alpha = (InferenceVariable)a.getT(); 325 ResolvedType U = a.getS(); 326 ResolvedType S = b.getS(); 327 ResolvedType T = b.getT(); 328 Substitution sub = Substitution.empty().withPair(alpha.getTypeParameterDeclaration(), U); 329 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSubtypeOfType(typeSolver, sub.apply(S), sub.apply(T))); 330 } 331 return currentConstraintSet; 332 }, newConstraintsSet); 333 334 // When a bound set contains a pair of bounds α <: S and α <: T, and there exists a supertype of S of the 335 // form G<S1, ..., Sn> and a supertype of T of the form G<T1, ..., Tn> (for some generic class or interface, G), 336 // then for all i (1 ≤ i ≤ n), if Si and Ti are types (not wildcards), the constraint formula ‹Si = Ti› is 337 // implied. 338 339 newConstraintsSet = forEachPairSubtypeAndSubtype((a, b, currentConstraintSet) -> { 340 if (isInferenceVariable(a.getS()) && isInferenceVariable(b.getS())) { 341 if (a.getT().isReferenceType() && b.getT().isReferenceType()) { 342 ResolvedReferenceType S = a.getT().asReferenceType(); 343 ResolvedReferenceType T = b.getT().asReferenceType(); 344 List<Pair<ResolvedReferenceType, ResolvedReferenceType>> pairs = findPairsOfCommonAncestors(S, T); 345 for (Pair<ResolvedReferenceType, ResolvedReferenceType> pair : pairs) { 346 for (int i=0;i<Math.min(pair.a.typeParametersValues().size(), pair.b.typeParametersValues().size()); i++) { 347 ResolvedType si = pair.a.typeParametersValues().get(i); 348 ResolvedType ti = pair.b.typeParametersValues().get(i); 349 if (!si.isWildcard() && !ti.isWildcard()) { 350 currentConstraintSet = currentConstraintSet.withConstraint(new TypeSameAsType(si, ti)); 351 } 352 } 353 } 354 } 355 } 356 return currentConstraintSet; 357 }, newConstraintsSet); 358 359 // SECTION Bounds Involving Capture Conversion 360 // 361 // When a bound set contains a bound of the form G<α1, ..., αn> = capture(G<A1, ..., An>), new bounds are 362 // implied and new constraint formulas may be implied, as follows. 363 364 for (Bound b : this.bounds.stream().filter(b -> b instanceof CapturesBound).collect(Collectors.toList())) { 365 CapturesBound capturesBound = (CapturesBound)b; 366 367 throw new UnsupportedOperationException(); 368 369 // Let P1, ..., Pn represent the type parameters of G and let B1, ..., Bn represent the bounds of these type 370 // parameters. Let θ represent the substitution [P1:=α1, ..., Pn:=αn]. Let R be a type that is not an inference 371 // variable (but is not necessarily a proper type). 372 // 373 // A set of bounds on α1, ..., αn is implied, constructed from the declared bounds of P1, ..., Pn as specified 374 // in §18.1.3. 375 // 376 // In addition, for all i (1 ≤ i ≤ n): 377 // 378 // - If Ai is not a wildcard, then the bound αi = Ai is implied. 379 // 380 // - If Ai is a wildcard of the form ?: 381 // 382 // - αi = R implies the bound false 383 // 384 // - αi <: R implies the constraint formula ‹Bi θ <: R› 385 // 386 // - R <: αi implies the bound false 387 // 388 // - If Ai is a wildcard of the form ? extends T: 389 // 390 // - αi = R implies the bound false 391 // 392 // - If Bi is Object, then αi <: R implies the constraint formula ‹T <: R› 393 // 394 // - If T is Object, then αi <: R implies the constraint formula ‹Bi θ <: R› 395 // 396 // - R <: αi implies the bound false 397 // 398 // - If Ai is a wildcard of the form ? super T: 399 // 400 // - αi = R implies the bound false 401 // 402 // - αi <: R implies the constraint formula ‹Bi θ <: R› 403 // 404 // - R <: αi implies the constraint formula ‹R <: T› 405 } 406 407 if (newConstraintsSet.isEmpty()) { 408 return this; 409 } else { 410 BoundSet newBounds = newConstraintsSet.reduce(typeSolver); 411 if (newBounds.isEmpty()) { 412 return this; 413 } 414 return this.incorporate(newBounds, typeSolver); 415 } 416 } 417 418 public boolean containsFalse() { 419 return bounds.stream().anyMatch(it -> it instanceof FalseBound); 420 } 421 422 private class VariableDependency { 423 private InferenceVariable depending; 424 private InferenceVariable dependedOn; 425 426 public VariableDependency(InferenceVariable depending, InferenceVariable dependedOn) { 427 this.depending = depending; 428 this.dependedOn = dependedOn; 429 } 430 431 public InferenceVariable getDepending() { 432 return depending; 433 } 434 435 public InferenceVariable getDependedOn() { 436 return dependedOn; 437 } 438 439 public boolean isReflexive() { 440 return dependedOn.equals(depending); 441 } 442 } 443 444 private Set<InferenceVariable> allInferenceVariables() { 445 Set<InferenceVariable> variables = new HashSet<>(); 446 for (Bound b : bounds) { 447 variables.addAll(b.usedInferenceVariables()); 448 } 449 return variables; 450 } 451 452 private boolean hasInstantiationFor(InferenceVariable v) { 453 for (Bound b : bounds) { 454 if (b.isAnInstantiationFor(v)) { 455 return true; 456 } 457 } 458 return false; 459 } 460 461 private Instantiation getInstantiationFor(InferenceVariable v) { 462 for (Bound b : bounds) { 463 if (b.isAnInstantiationFor(v)) { 464 return b.isAnInstantiation().get(); 465 } 466 } 467 throw new IllegalArgumentException(); 468 } 469 470 private boolean thereIsSomeJSuchThatβequalAlphaJ(Set<InferenceVariable> alphas, InferenceVariable beta) { 471 for (InferenceVariable alphaJ : alphas) { 472 for (Bound b : bounds) { 473 if (b instanceof SameAsBound) { 474 SameAsBound sameAsBound = (SameAsBound)b; 475 if (sameAsBound.getS().equals(alphaJ) && sameAsBound.getT().equals(beta)) { 476 return true; 477 } 478 if (sameAsBound.getT().equals(alphaJ) && sameAsBound.getS().equals(beta)) { 479 return true; 480 } 481 } 482 } 483 } 484 return false; 485 } 486 487 private <T> List<Set<T>> buildAllSubsetsOfSize(Set<T> allElements, int desiredSize) { 488 if (desiredSize == allElements.size()) { 489 return Arrays.asList(allElements); 490 } else { 491 List<Set<T>> res = new LinkedList<>(); 492 for (T element : allElements) { 493 Set<T> subset = allButOne(allElements, element); 494 res.addAll(buildAllSubsetsOfSize(subset, desiredSize)); 495 } 496 return res; 497 } 498 } 499 500 private <T> Set<T> allButOne(Set<T> elements, T element) { 501 Set<T> set = new HashSet<T>(elements); 502 set.remove(element); 503 return set; 504 } 505 506 /** 507 * there exists no non-empty proper subset of { α1, ..., αn } with this property. 508 */ 509 private Optional<Set<InferenceVariable>> smallestSetWithProperty(Set<InferenceVariable> uninstantiatedVariables, 510 List<VariableDependency> dependencies) { 511 for (int i=1;i<=uninstantiatedVariables.size();i++) { 512 for (Set<InferenceVariable> aSubSet : buildAllSubsetsOfSize(uninstantiatedVariables, i)){ 513 if (hasProperty(aSubSet, dependencies)) { 514 return Optional.of(aSubSet); 515 } 516 } 517 } 518 return Optional.empty(); 519 } 520 521 /** 522 * if αi depends on the resolution of a variable β, then either β has an instantiation 523 * or there is some j such that β = αj 524 * @return 525 */ 526 private boolean hasProperty(Set<InferenceVariable> alphas, List<VariableDependency> dependencies) { 527 for (InferenceVariable alphaI: alphas) { 528 for (InferenceVariable beta: dependencies.stream() 529 .filter(d -> d.depending.equals(alphaI)) 530 .filter(d -> !d.isReflexive()) 531 .map(d -> d.dependedOn) 532 .collect(Collectors.toList())) { 533 if (!hasInstantiationFor(beta) && !thereIsSomeJSuchThatβequalAlphaJ(alphas, beta)) { 534 return false; 535 } 536 } 537 } 538 return true; 539 } 540 541 /** 542 * Examines the bounds on an inference variable and determines an instantiation that is compatible with those 543 * bounds. It also decides the order in which interdependent inference variables are to be resolved. 544 */ 545 public Optional<InstantiationSet> performResolution(List<InferenceVariable> variablesToResolve, TypeSolver typeSolver) { 546 547 if (this.containsFalse()) { 548 return Optional.empty(); 549 } 550 551 List<VariableDependency> dependencies = new LinkedList<>(); 552 553 // Given a bound set that does not contain the bound false, a subset of the inference variables mentioned by 554 // the bound set may be resolved. This means that a satisfactory instantiation may be added to the set for each 555 // inference variable, until all the requested variables have instantiations. 556 // 557 // Dependencies in the bound set may require that the variables be resolved in a particular order, or that 558 // additional variables be resolved. Dependencies are specified as follows: 559 // 560 // - Given a bound of one of the following forms, where T is either an inference variable β or a type that 561 // mentions β: 562 // 563 // - α = T 564 // 565 // - α <: T 566 // 567 // - T = α 568 // 569 // - T <: α 570 // 571 // If α appears on the left-hand side of another bound of the form G<..., α, ...> = capture(G<...>), then β 572 // depends on the resolution of α. Otherwise, α depends on the resolution of β. 573 574 for (Bound b : bounds) { 575 if (b instanceof CapturesBound) { 576 throw new UnsupportedOperationException(); 577 } 578 } 579 580 // - An inference variable α appearing on the left-hand side of a bound of the form 581 // G<..., α, ...> = capture(G<...>) depends on the resolution of every other inference variable mentioned in 582 // this bound (on both sides of the = sign). 583 584 for (Bound b : bounds) { 585 if (b instanceof CapturesBound) { 586 throw new UnsupportedOperationException(); 587 } 588 } 589 590 // - An inference variable α depends on the resolution of an inference variable β if there exists an inference 591 // variable γ such that α depends on the resolution of γ and γ depends on the resolution of β. 592 593 for (int i=0;i<dependencies.size();i++) { 594 VariableDependency di = dependencies.get(i); 595 for (int j=i+1;j<dependencies.size();j++) { 596 VariableDependency dj = dependencies.get(j); 597 if (di.dependedOn.equals(dj.depending)) { 598 dependencies.add(new VariableDependency(di.getDepending(), dj.getDependedOn())); 599 } 600 } 601 } 602 603 // - An inference variable α depends on the resolution of itself. 604 605 for (InferenceVariable v : allInferenceVariables()) { 606 dependencies.add(new VariableDependency(v, v)); 607 } 608 609 // Given a set of inference variables to resolve, let V be the union of this set and all variables upon which 610 // the resolution of at least one variable in this set depends. 611 612 Set<InferenceVariable> V = new HashSet<>(); 613 V.addAll(variablesToResolve); 614 for (VariableDependency dependency : dependencies) { 615 if (variablesToResolve.contains(dependency.depending)) { 616 V.add(dependency.dependedOn); 617 } 618 } 619 620 // If every variable in V has an instantiation, then resolution succeeds and this procedure terminates. 621 622 boolean ok = true; 623 for (InferenceVariable v : V) { 624 if (!hasInstantiationFor(v)) { 625 ok = false; 626 } 627 } 628 if (ok) { 629 InstantiationSet instantiationSet = InstantiationSet.empty(); 630 for (InferenceVariable v : V) { 631 instantiationSet = instantiationSet.withInstantiation(getInstantiationFor(v)); 632 } 633 return Optional.of(instantiationSet); 634 } 635 636 // Otherwise, let { α1, ..., αn } be a non-empty subset of uninstantiated variables in V such that i) 637 // for all i (1 ≤ i ≤ n), if αi depends on the resolution of a variable β, then either β has an instantiation 638 // or there is some j such that β = αj; and ii) there exists no non-empty proper subset of { α1, ..., αn } 639 // with this property. 640 641 Set<InferenceVariable> uninstantiatedPortionOfV = new HashSet<>(); 642 for (InferenceVariable v : V) { 643 if (!hasInstantiationFor(v)) { 644 uninstantiatedPortionOfV.add(v); 645 } 646 } 647 for (Set<InferenceVariable> alphas: allSetsWithProperty(uninstantiatedPortionOfV, dependencies)) { 648 649 // Resolution proceeds by generating an instantiation for each of α1, ..., αn based on the 650 // bounds in the bound set: 651 652 boolean hasSomeCaptureForAlphas = alphas.stream().anyMatch( 653 alphaI -> appearInLeftPartOfCapture(alphaI) 654 ); 655 656 // - If the bound set does not contain a bound of the form G<..., αi, ...> = capture(G<...>) 657 // for all i (1 ≤ i ≤ n), then a candidate instantiation Ti is defined for each αi: 658 659 if (!hasSomeCaptureForAlphas) { 660 BoundSet newBounds = BoundSet.empty(); 661 for (InferenceVariable alphaI : alphas) { 662 Set<ResolvedType> properLowerBounds = bounds.stream() 663 .filter(b -> b.isProperLowerBoundFor(alphaI).isPresent()) 664 .map(b -> b.isProperLowerBoundFor(alphaI).get().getProperType()) 665 .collect(Collectors.toSet()); 666 667 ResolvedType Ti = null; 668 669 // - If αi has one or more proper lower bounds, L1, ..., Lk, then Ti = lub(L1, ..., Lk) (§4.10.4). 670 671 if (properLowerBounds.size() > 0) { 672 Ti = leastUpperBound(properLowerBounds); 673 } 674 675 // - Otherwise, if the bound set contains throws αi, and the proper upper bounds of αi are, at most, 676 // Exception, Throwable, and Object, then Ti = RuntimeException. 677 678 boolean throwsBound = bounds.stream().anyMatch(b -> b.isThrowsBoundOn(alphaI)); 679 if (Ti == null && throwsBound && properUpperBoundsAreAtMostExceptionThrowableAndObject(alphaI)) { 680 Ti = new ReferenceTypeImpl(typeSolver.solveType(RuntimeException.class.getCanonicalName()), typeSolver); 681 } 682 683 // - Otherwise, where αi has proper upper bounds U1, ..., Uk, Ti = glb(U1, ..., Uk) (§5.1.10). 684 685 if (Ti == null) { 686 Set<ResolvedType> properUpperBounds = bounds.stream() 687 .filter(b -> b.isProperUpperBoundFor(alphaI).isPresent()) 688 .map(b -> b.isProperUpperBoundFor(alphaI).get().getProperType()) 689 .collect(Collectors.toSet()); 690 if (properUpperBounds.size() == 0) { 691 throw new IllegalStateException(); 692 } 693 Ti = glb(properUpperBounds); 694 } 695 696 newBounds = newBounds.withBound(new SameAsBound(alphaI, Ti)); 697 } 698 699 // The bounds α1 = T1, ..., αn = Tn are incorporated with the current bound set. 700 701 BoundSet incorporatedBoundSet = this.incorporate(newBounds, typeSolver); 702 703 // If the result does not contain the bound false, then the result becomes the new bound set, and resolution 704 // proceeds by selecting a new set of variables to instantiate (if necessary), as described above. 705 706 if (!incorporatedBoundSet.containsFalse()) { 707 return incorporatedBoundSet.performResolution(variablesToResolve, typeSolver); 708 } 709 710 // Otherwise, the result contains the bound false, so a second attempt is made to instantiate { α1, ..., αn } 711 // by performing the step below. 712 713 throw new UnsupportedOperationException(); 714 } 715 716 // - If the bound set contains a bound of the form G<..., αi, ...> = capture(G<...>) for some i (1 ≤ i ≤ n), or; 717 718 else { 719 720 // If the bound set produced in the step above contains the bound false; 721 // 722 // then let Y1, ..., Yn be fresh type variables whose bounds are as follows: 723 // 724 // - For all i (1 ≤ i ≤ n), if αi has one or more proper lower bounds L1, ..., Lk, then let the lower bound 725 // of Yi be lub(L1, ..., Lk); if not, then Yi has no lower bound. 726 // 727 // - For all i (1 ≤ i ≤ n), where αi has upper bounds U1, ..., Uk, let the upper bound of Yi be 728 // glb(U1 θ, ..., Uk θ), where θ is the substitution [α1:=Y1, ..., αn:=Yn]. 729 // 730 // If the type variables Y1, ..., Yn do not have well-formed bounds (that is, a lower bound is not a subtype 731 // of an upper bound, or an intersection type is inconsistent), then resolution fails. 732 // 733 // Otherwise, for all i (1 ≤ i ≤ n), all bounds of the form G<..., αi, ...> = capture(G<...>) are removed 734 // from the current bound set, and the bounds α1 = Y1, ..., αn = Yn are incorporated. 735 // 736 // If the result does not contain the bound false, then the result becomes the new bound set, and resolution 737 // proceeds by selecting a new set of variables to instantiate (if necessary), as described above. 738 // 739 // Otherwise, the result contains the bound false, and resolution fails. 740 741 throw new UnsupportedOperationException(); 742 } 743 } 744 return Optional.empty(); 745 } 746 747 private Set<Set<InferenceVariable>> allPossibleSetsWithProperty(Set<InferenceVariable> allElements, List<VariableDependency> dependencies) { 748 Set<Set<InferenceVariable>> result = new HashSet<>(); 749 for (int i=1;i<=allElements.size();i++) { 750 for (Set<InferenceVariable> aSubSet : buildAllSubsetsOfSize(allElements, i)){ 751 if (hasProperty(aSubSet, dependencies)) { 752 result.add(aSubSet); 753 } 754 } 755 } 756 return result; 757 } 758 759 private boolean thereAreProperSubsets(Set<InferenceVariable> aSet, Set<Set<InferenceVariable>> allPossibleSets) { 760 for (Set<InferenceVariable> anotherSet : allPossibleSets) { 761 if (!anotherSet.equals(aSet)) { 762 if (isTheFirstAProperSubsetOfTheSecond(anotherSet, aSet)) { 763 return true; 764 } 765 } 766 } 767 return false; 768 } 769 770 private boolean isTheFirstAProperSubsetOfTheSecond(Set<InferenceVariable> subset, Set<InferenceVariable> originalSet) { 771 return originalSet.containsAll(subset) && originalSet.size() > subset.size(); 772 } 773 774 private Set<Set<InferenceVariable>> allSetsWithProperty(Set<InferenceVariable> allElements, List<VariableDependency> dependencies) { 775 Set<Set<InferenceVariable>> allPossibleSets = allPossibleSetsWithProperty(allElements, dependencies); 776 Set<Set<InferenceVariable>> selected = new HashSet<>(); 777 for (Set<InferenceVariable> aSet : allPossibleSets) { 778 if (!thereAreProperSubsets(aSet, allPossibleSets)) { 779 selected.add(aSet); 780 } 781 } 782 return selected; 783 } 784 785 private boolean properUpperBoundsAreAtMostExceptionThrowableAndObject(InferenceVariable inferenceVariable) { 786 throw new UnsupportedOperationException(); 787 } 788 789 private boolean appearInLeftPartOfCapture(InferenceVariable inferenceVariable) { 790 for (Bound b : bounds) { 791 if (b instanceof CapturesBound) { 792 CapturesBound capturesBound = (CapturesBound)b; 793 if (capturesBound.getInferenceVariables().contains(inferenceVariable)) { 794 return true; 795 } 796 } 797 } 798 return false; 799 } 800 801 public List<Bound> getProperUpperBoundsFor(InferenceVariable inferenceVariable) { 802 return bounds.stream().filter(b -> b.isProperUpperBoundFor(inferenceVariable).isPresent()).collect(Collectors.toList()); 803 } 804} 805