framework.src.org.checkerframework.qualframework.poly.Wildcard Maven / Gradle / Ivy
package org.checkerframework.qualframework.poly;
import java.util.*;
/** A qualifier wildcard, bounded above and below by {@link PolyQual}s.
*/
public class Wildcard {
private final PolyQual lower;
private final PolyQual upper;
public Wildcard(PolyQual lower, PolyQual upper) {
// Don't let the user pass in `null`. We use `null` to represent the
// special empty wildcard.
if (lower == null || upper == null) {
throw new IllegalArgumentException("wildcard bounds may not be null");
}
this.lower = lower;
this.upper = upper;
}
public Wildcard(PolyQual qual) {
this(qual, qual);
}
public Wildcard(Q groundLower, Q groundUpper) {
this(new PolyQual.GroundQual(groundLower), new PolyQual.GroundQual(groundUpper));
}
public Wildcard(Q groundQual) {
this(new PolyQual.GroundQual(groundQual));
}
/**
* Force the user to write `Wildcard.empty()` instead of `new Wildcard()`,
* to make it clear that they're getting something special, rather than
* a normal wildcard with default bounds or something like that.
*/
private Wildcard() {
this.lower = null;
this.upper = null;
}
/** Produce the empty wildcard. */
public static Wildcard empty() {
return new Wildcard();
}
/** Get the lower bound of the wildcard, or {@code null} if this is the
* empty wildcard. */
public PolyQual getLowerBound() {
return this.lower;
}
/** Get the upper bound of the wildcard, or {@code null} if this is the
* empty wildcard. */
public PolyQual getUpperBound() {
return this.upper;
}
/** Check if this is the empty wildcard. */
public boolean isEmpty() {
return this.lower == null;
}
/** Substitute wildcards for qualifier parameters. */
public Wildcard substitute(Map> substs) {
Map> lowerSubsts = new HashMap<>();
Map> upperSubsts = new HashMap<>();
for (String k : substs.keySet()) {
lowerSubsts.put(k, substs.get(k).getLowerBound());
upperSubsts.put(k, substs.get(k).getUpperBound());
}
PolyQual newLower = lower.substitute(lowerSubsts);
PolyQual newUpper = upper.substitute(upperSubsts);
return new Wildcard(newLower, newUpper);
}
/** Combine with another wildcard, using the provided {@link
* CombiningOperation}s for the upper and lower bounds.
*/
public Wildcard combineWith(Wildcard other,
CombiningOperation lowerOp, CombiningOperation upperOp) {
return new Wildcard(
this.getLowerBound().combineWith(other.getLowerBound(), lowerOp),
this.getUpperBound().combineWith(other.getUpperBound(), upperOp));
}
@Override
public boolean equals(Object o) {
if (o == null || o.getClass() != this.getClass()) {
return false;
}
@SuppressWarnings("rawtypes")
Wildcard other = (Wildcard)o;
return this.lower.equals(other.lower)
&& this.upper.equals(other.upper);
}
@Override
public int hashCode() {
return this.lower.hashCode() * 37
+ this.upper.hashCode() * 59;
}
@Override
public String toString() {
if (this.isEmpty()) {
return "ø";
} else if (lower.equals(upper)) {
return lower.toString();
} else {
return "? ∈ [" + lower + ".." + upper + "]";
}
}
}