blob: b0ed7c8d1029cc36b562c8b171d312e833ea440c [file] [log] [blame]
package org.checkerframework.framework.util.typeinference.solver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.framework.util.AnnotationMirrorSet;
import org.checkerframework.framework.util.typeinference.solver.TargetConstraints.Equalities;
import org.checkerframework.framework.util.typeinference.solver.TargetConstraints.Subtypes;
import org.checkerframework.framework.util.typeinference.solver.TargetConstraints.Supertypes;
/**
* ConstraintMap holds simplified versions of the TUConstraints for ALL type variable for which we
* are inferring an argument. The ConstraintMap is edited on the fly as the various solvers work
* (unlike the AF/TU Constraints which are immutable).
*
* <p>This really consists of these things:
*
* <ol>
* <li>a Map({@code target => constraints for target})
* <li>Methods to easily build up the constraints in the map
* <li>A getter for the constraints of individual targets.
* </ol>
*
* Note: This class, along with TargetConstraints, uses a lot of mutable state and few
* setters/getters be careful. This choice was made as it makes the resulting code more readable.
*/
public class ConstraintMap {
private final Map<TypeVariable, TargetConstraints> targetToRecords = new LinkedHashMap<>();
public ConstraintMap(Set<TypeVariable> targets) {
for (final TypeVariable target : targets) {
targetToRecords.put(target, new TargetConstraints(target));
}
}
public ConstraintMap(final ConstraintMap toCopy) {
this.targetToRecords.putAll(toCopy.targetToRecords);
}
/** Gets the equality, subtypes, and supertypes constraints for a particular target. */
public TargetConstraints getConstraints(final TypeVariable target) {
return targetToRecords.get(target);
}
/**
* Returns the set of all targets passed to the constructor of this constraint map (a target will
* appear in this list whether or not it has any constraints added).
*
* @return the set of all targets passed to the constructor of this constraint map (a target will
* appear in this list whether or not it has any constraints added)
*/
public Set<TypeVariable> getTargets() {
return targetToRecords.keySet();
}
/**
* Add a constraint indicating that the equivalent is equal to target in the given qualifier
* hierarchies.
*/
public void addTargetEquality(
final TypeVariable target, final TypeVariable equivalent, AnnotationMirrorSet hierarchies) {
final Equalities equalities = targetToRecords.get(target).equalities;
final AnnotationMirrorSet equivalentTops =
equalities.targets.computeIfAbsent(equivalent, __ -> new AnnotationMirrorSet());
equivalentTops.addAll(hierarchies);
}
/**
* Add a constraint indicating that target has primary annotations equal to the given annotations.
*/
public void addPrimaryEqualities(
final TypeVariable target,
QualifierHierarchy qualHierarchy,
final AnnotationMirrorSet annos) {
final Equalities equalities = targetToRecords.get(target).equalities;
for (final AnnotationMirror anno : annos) {
final AnnotationMirror top = qualHierarchy.getTopAnnotation(anno);
if (!equalities.primaries.containsKey(top)) {
equalities.primaries.put(top, anno);
}
}
}
/**
* Add a constraint indicating that target is a supertype of subtype in the given qualifier
* hierarchies.
*
* @param hierarchies a set of TOP annotations
*/
public void addTargetSupertype(
final TypeVariable target, final TypeVariable subtype, AnnotationMirrorSet hierarchies) {
final Supertypes supertypes = targetToRecords.get(target).supertypes;
final AnnotationMirrorSet supertypeTops =
supertypes.targets.computeIfAbsent(subtype, __ -> new AnnotationMirrorSet());
supertypeTops.addAll(hierarchies);
}
/**
* Add a constraint indicating that target is a supertype of subtype in the given qualifier
* hierarchies.
*
* @param hierarchies a set of TOP annotations
*/
public void addTypeSupertype(
final TypeVariable target,
final AnnotatedTypeMirror subtype,
AnnotationMirrorSet hierarchies) {
final Supertypes supertypes = targetToRecords.get(target).supertypes;
final AnnotationMirrorSet supertypeTops =
supertypes.types.computeIfAbsent(subtype, __ -> new AnnotationMirrorSet());
supertypeTops.addAll(hierarchies);
}
/**
* Add a constraint indicating that target's primary annotations are subtypes of the given
* annotations.
*/
public void addPrimarySupertype(
final TypeVariable target,
QualifierHierarchy qualifierHierarchy,
final AnnotationMirrorSet annos) {
final Supertypes supertypes = targetToRecords.get(target).supertypes;
for (final AnnotationMirror anno : annos) {
final AnnotationMirror top = qualifierHierarchy.getTopAnnotation(anno);
AnnotationMirrorSet entries =
supertypes.primaries.computeIfAbsent(top, __ -> new AnnotationMirrorSet());
entries.add(anno);
}
}
/**
* Add a constraint indicating that target is a subtype of supertype in the given qualifier
* hierarchies.
*
* @param hierarchies a set of TOP annotations
*/
public void addTargetSubtype(
final TypeVariable target, final TypeVariable supertype, AnnotationMirrorSet hierarchies) {
final Subtypes subtypes = targetToRecords.get(target).subtypes;
final AnnotationMirrorSet subtypesTops =
subtypes.targets.computeIfAbsent(supertype, __ -> new AnnotationMirrorSet());
subtypesTops.addAll(hierarchies);
}
/**
* Add a constraint indicating that target is a subtype of supertype in the given qualifier
* hierarchies.
*
* @param hierarchies a set of TOP annotations
*/
public void addTypeSubtype(
final TypeVariable target,
final AnnotatedTypeMirror supertype,
AnnotationMirrorSet hierarchies) {
final Subtypes subtypes = targetToRecords.get(target).subtypes;
final AnnotationMirrorSet subtypesTops =
subtypes.types.computeIfAbsent(supertype, __ -> new AnnotationMirrorSet());
subtypesTops.addAll(hierarchies);
}
/**
* Add a constraint indicating that target's primary annotations are subtypes of the given
* annotations.
*/
public void addPrimarySubtypes(
final TypeVariable target,
QualifierHierarchy qualifierHierarchy,
final AnnotationMirrorSet annos) {
final Subtypes subtypes = targetToRecords.get(target).subtypes;
for (final AnnotationMirror anno : annos) {
final AnnotationMirror top = qualifierHierarchy.getTopAnnotation(anno);
AnnotationMirrorSet entries =
subtypes.primaries.computeIfAbsent(top, __ -> new AnnotationMirrorSet());
entries.add(anno);
}
}
/**
* Add a constraint indicating that target is equal to type in the given hierarchies.
*
* @param hierarchies a set of TOP annotations
*/
public void addTypeEqualities(
TypeVariable target, AnnotatedTypeMirror type, AnnotationMirrorSet hierarchies) {
final Equalities equalities = targetToRecords.get(target).equalities;
final AnnotationMirrorSet equalityTops =
equalities.types.computeIfAbsent(type, __ -> new AnnotationMirrorSet());
equalityTops.addAll(hierarchies);
}
}