use of org.checkerframework.framework.util.AnnotationMirrorSet in project checker-framework by typetools.
the class EqualitiesSolver method updateTargetsWithPartiallyInferredType.
// If we determined that this target T1 is equal to a type ATM in hierarchies @A,@B,@C
// for each of those hierarchies, if a target is equal to T1 in that hierarchy it is also equal
// to ATM
// e.g.
// if : T1 == @A @B @C ATM in only the A,B hierarchies
// and T1 == T2 only in @A hierarchy
//
// then T2 == @A @B @C only in the @A hierarchy
//
public boolean updateTargetsWithPartiallyInferredType(final Equalities equalities, ConstraintMap constraintMap, AnnotatedTypeFactory typeFactory) {
boolean updated = false;
if (!equalities.types.isEmpty()) {
if (equalities.types.size() != 1) {
ErrorReporter.errorAbort("Equalities should have at most 1 constraint.");
}
Entry<AnnotatedTypeMirror, AnnotationMirrorSet> remainingTypeEquality;
remainingTypeEquality = equalities.types.entrySet().iterator().next();
final AnnotatedTypeMirror remainingType = remainingTypeEquality.getKey();
final AnnotationMirrorSet remainingHierarchies = remainingTypeEquality.getValue();
// update targets
for (Map.Entry<TypeVariable, AnnotationMirrorSet> targetToHierarchies : equalities.targets.entrySet()) {
final TypeVariable equalTarget = targetToHierarchies.getKey();
final AnnotationMirrorSet hierarchies = targetToHierarchies.getValue();
final AnnotationMirrorSet equalTypeHierarchies = new AnnotationMirrorSet(remainingHierarchies);
equalTypeHierarchies.retainAll(hierarchies);
final Map<AnnotatedTypeMirror, AnnotationMirrorSet> otherTargetsEqualTypes = constraintMap.getConstraints(equalTarget).equalities.types;
AnnotationMirrorSet equalHierarchies = otherTargetsEqualTypes.get(remainingType);
if (equalHierarchies == null) {
equalHierarchies = new AnnotationMirrorSet(equalTypeHierarchies);
otherTargetsEqualTypes.put(remainingType, equalHierarchies);
updated = true;
} else {
final int size = equalHierarchies.size();
equalHierarchies.addAll(equalTypeHierarchies);
updated = size == equalHierarchies.size();
}
}
}
return updated;
}
use of org.checkerframework.framework.util.AnnotationMirrorSet in project checker-framework by typetools.
the class EqualitiesSolver method rewriteWithInferredType.
/**
* Let Ti be a target type parameter. When we reach this method we have inferred an argument,
* Ai, for Ti
*
* <p>However, there still may be constraints of the form {@literal Ti = Tj}, {@literal Ti <:
* Tj}, {@literal Tj <: Ti} in the constraint map. In this case we need to replace Ti with the
* type. That is, they become {@literal Ai = Tj}, {@literal Ai <: Tj}, and {@literal Tj <: Ai}
*
* <p>To do this, we find the TargetConstraints for Tj and add these constraints to the
* appropriate map in TargetConstraints. We can then clear the constraints for the current
* target since we have inferred a type.
*
* @param target the target for which we have inferred a concrete type argument
* @param type the type inferred
*/
private void rewriteWithInferredType(final TypeVariable target, final AnnotatedTypeMirror type, final ConstraintMap constraints) {
final TargetConstraints targetRecord = constraints.getConstraints(target);
final Map<TypeVariable, AnnotationMirrorSet> equivalentTargets = targetRecord.equalities.targets;
// hierarchies as the inferred type
for (final Entry<TypeVariable, AnnotationMirrorSet> eqEntry : equivalentTargets.entrySet()) {
constraints.addTypeEqualities(eqEntry.getKey(), type, eqEntry.getValue());
}
for (TypeVariable otherTarget : constraints.getTargets()) {
if (otherTarget != target) {
final TargetConstraints record = constraints.getConstraints(otherTarget);
// each target that was equivalent to this one needs to be equivalent in the same
// hierarchies as the inferred type
final AnnotationMirrorSet hierarchies = record.equalities.targets.get(target);
if (hierarchies != null) {
record.equalities.targets.remove(target);
constraints.addTypeEqualities(otherTarget, type, hierarchies);
}
// otherTypes may have AnnotatedTypeVariables of type target, run substitution on
// these with type
Map<AnnotatedTypeMirror, AnnotationMirrorSet> toIterate = new LinkedHashMap<>(record.equalities.types);
record.equalities.types.clear();
for (AnnotatedTypeMirror otherType : toIterate.keySet()) {
final AnnotatedTypeMirror copy = TypeArgInferenceUtil.substitute(target, type, otherType);
final AnnotationMirrorSet otherHierarchies = toIterate.get(otherType);
record.equalities.types.put(copy, otherHierarchies);
}
}
}
for (TypeVariable otherTarget : constraints.getTargets()) {
if (otherTarget != target) {
final TargetConstraints record = constraints.getConstraints(otherTarget);
// each target that was equivalent to this one needs to be equivalent in the same
// hierarchies as the inferred type
final AnnotationMirrorSet hierarchies = record.supertypes.targets.get(target);
if (hierarchies != null) {
record.supertypes.targets.remove(target);
constraints.addTypeEqualities(otherTarget, type, hierarchies);
}
// otherTypes may have AnnotatedTypeVariables of type target, run substitution on
// these with type
Map<AnnotatedTypeMirror, AnnotationMirrorSet> toIterate = new LinkedHashMap<>(record.supertypes.types);
record.supertypes.types.clear();
for (AnnotatedTypeMirror otherType : toIterate.keySet()) {
final AnnotatedTypeMirror copy = TypeArgInferenceUtil.substitute(target, type, otherType);
final AnnotationMirrorSet otherHierarchies = toIterate.get(otherType);
record.supertypes.types.put(copy, otherHierarchies);
}
}
}
targetRecord.equalities.clear();
targetRecord.supertypes.clear();
}
use of org.checkerframework.framework.util.AnnotationMirrorSet in project checker-framework by typetools.
the class EqualitiesSolver method rewriteWithInferredTarget.
/**
* Let Ti be a target type parameter. When we reach this method we have inferred that Ti has the
* exact same argument as another target Tj
*
* <p>Therefore, we want to stop solving for Ti and instead wait till we solve for Tj and use
* that result.
*
* <p>Let ATM be any annotated type mirror and Tk be a target type parameter where k != i and k
* != j Even though we've inferred Ti = Tj, there still may be constraints of the form Ti = ATM
* or {@literal Ti <: Tk} These constraints are still useful for inferring a argument for Ti/Tj.
* So, we replace Ti in these constraints with Tj and place those constraints in the
* TargetConstraints object for Tj.
*
* <p>We then clear the constraints for Ti.
*
* @param target the target for which we know another target is exactly equal to this target
* @param inferredTarget the other target inferred to be equal
*/
private void rewriteWithInferredTarget(final TypeVariable target, final TypeVariable inferredTarget, final ConstraintMap constraints, final AnnotatedTypeFactory typeFactory) {
final TargetConstraints targetRecord = constraints.getConstraints(target);
final Map<AnnotatedTypeMirror, AnnotationMirrorSet> equivalentTypes = targetRecord.equalities.types;
final Map<AnnotatedTypeMirror, AnnotationMirrorSet> supertypes = targetRecord.supertypes.types;
// to the inferred target
for (final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> eqEntry : equivalentTypes.entrySet()) {
constraints.addTypeEqualities(inferredTarget, eqEntry.getKey(), eqEntry.getValue());
}
for (final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> superEntry : supertypes.entrySet()) {
constraints.addTypeSupertype(inferredTarget, superEntry.getKey(), superEntry.getValue());
}
for (TypeVariable otherTarget : constraints.getTargets()) {
if (otherTarget != target && otherTarget != inferredTarget) {
final TargetConstraints record = constraints.getConstraints(otherTarget);
// each target that was equivalent to this one needs to be equivalent in the same
// hierarchies as the inferred target
final AnnotationMirrorSet hierarchies = record.equalities.targets.get(target);
if (hierarchies != null) {
record.equalities.targets.remove(target);
constraints.addTargetEquality(otherTarget, inferredTarget, hierarchies);
}
// otherTypes may have AnnotatedTypeVariables of type target, run substitution on
// these with type
Map<AnnotatedTypeMirror, AnnotationMirrorSet> toIterate = new LinkedHashMap<>(record.equalities.types);
record.equalities.types.clear();
for (AnnotatedTypeMirror otherType : toIterate.keySet()) {
final AnnotatedTypeMirror copy = TypeArgInferenceUtil.substitute(target, createAnnotatedTypeVar(target, typeFactory), otherType);
final AnnotationMirrorSet otherHierarchies = toIterate.get(otherType);
record.equalities.types.put(copy, otherHierarchies);
}
}
}
for (TypeVariable otherTarget : constraints.getTargets()) {
if (otherTarget != target && otherTarget != inferredTarget) {
final TargetConstraints record = constraints.getConstraints(otherTarget);
final AnnotationMirrorSet hierarchies = record.supertypes.targets.get(target);
if (hierarchies != null) {
record.supertypes.targets.remove(target);
constraints.addTargetSupertype(otherTarget, inferredTarget, hierarchies);
}
// otherTypes may have AnnotatedTypeVariables of type target, run substitution on
// these with type
Map<AnnotatedTypeMirror, AnnotationMirrorSet> toIterate = new LinkedHashMap<>(record.supertypes.types);
record.supertypes.types.clear();
for (AnnotatedTypeMirror otherType : toIterate.keySet()) {
final AnnotatedTypeMirror copy = TypeArgInferenceUtil.substitute(target, createAnnotatedTypeVar(target, typeFactory), otherType);
final AnnotationMirrorSet otherHierarchies = toIterate.get(otherType);
record.supertypes.types.put(copy, otherHierarchies);
}
}
}
targetRecord.equalities.clear();
targetRecord.supertypes.clear();
}
use of org.checkerframework.framework.util.AnnotationMirrorSet in project checker-framework by typetools.
the class EqualitiesSolver method mergeTypesAndPrimaries.
/**
* @param typesToHierarchies a mapping of (types → hierarchies) that indicate that the
* argument being inferred is equal to the types in each of the hierarchies
* @param primaries a map (hierarchy → annotation in hierarchy) where the annotation in
* hierarchy is equal to the primary annotation on the argument being inferred
* @param tops the set of top annotations in the qualifier hierarchy
* @return a concrete type argument or null if there was not enough information to infer one
*/
private InferredType mergeTypesAndPrimaries(Map<AnnotatedTypeMirror, AnnotationMirrorSet> typesToHierarchies, AnnotationMirrorMap<AnnotationMirror> primaries, final AnnotationMirrorSet tops) {
final AnnotationMirrorSet missingAnnos = new AnnotationMirrorSet(tops);
Iterator<Entry<AnnotatedTypeMirror, AnnotationMirrorSet>> entryIterator = typesToHierarchies.entrySet().iterator();
if (!entryIterator.hasNext()) {
ErrorReporter.errorAbort("Merging a list of empty types!");
}
final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> head = entryIterator.next();
AnnotatedTypeMirror mergedType = head.getKey();
missingAnnos.removeAll(head.getValue());
// AnnotatedDeclaredTypes, AnnotatedTypeVariables, and AnnotatedArrayTypes
while (entryIterator.hasNext() && !missingAnnos.isEmpty()) {
final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> current = entryIterator.next();
final AnnotatedTypeMirror currentType = current.getKey();
final AnnotationMirrorSet currentHierarchies = current.getValue();
AnnotationMirrorSet found = new AnnotationMirrorSet();
for (AnnotationMirror top : missingAnnos) {
if (currentHierarchies.contains(top)) {
final AnnotationMirror newAnno = currentType.getAnnotationInHierarchy(top);
if (newAnno != null) {
mergedType.replaceAnnotation(newAnno);
found.add(top);
} else if (mergedType.getKind() == TypeKind.TYPEVAR && currentType.getUnderlyingType().equals(mergedType.getUnderlyingType())) {
// the options here are we are merging with the same typevar, in which case
// we can just remove the annotation from the missing list
found.add(top);
} else {
// otherwise the other type is missing an annotation
ErrorReporter.errorAbort("Missing annotation.\n" + "\nmergedType=" + mergedType + "\ncurrentType=" + currentType);
}
}
}
missingAnnos.removeAll(found);
}
// add all the annotations from the primaries
final AnnotationMirrorSet foundHierarchies = new AnnotationMirrorSet();
for (final AnnotationMirror top : missingAnnos) {
final AnnotationMirror anno = primaries.get(top);
if (anno != null) {
foundHierarchies.add(top);
mergedType.replaceAnnotation(anno);
}
}
typesToHierarchies.clear();
if (missingAnnos.isEmpty()) {
return new InferredType(mergedType);
}
// TODO: we probably can do more with this information than just putting it back into the
// TODO: ConstraintMap (which is what's happening here)
final AnnotationMirrorSet hierarchies = new AnnotationMirrorSet(tops);
hierarchies.removeAll(missingAnnos);
typesToHierarchies.put(mergedType, hierarchies);
return null;
}
use of org.checkerframework.framework.util.AnnotationMirrorSet in project checker-framework by typetools.
the class SupertypesSolver method groundMissingHierarchies.
/**
* For each type in typeToHierarchies, if that type does not have a corresponding annotation for
* a given hierarchy replace it with the corresponding value in lowerBoundAnnos
*/
public static AnnotatedTypeMirror groundMissingHierarchies(final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> typeToHierarchies, final AnnotationMirrorMap<AnnotationMirror> lowerBoundAnnos) {
final AnnotationMirrorSet presentHierarchies = typeToHierarchies.getValue();
final AnnotationMirrorSet missingAnnos = new AnnotationMirrorSet();
for (AnnotationMirror top : lowerBoundAnnos.keySet()) {
if (!presentHierarchies.contains(top)) {
missingAnnos.add(lowerBoundAnnos.get(top));
}
}
if (!missingAnnos.isEmpty()) {
AnnotatedTypeMirror copy = typeToHierarchies.getKey().deepCopy();
copy.replaceAnnotations(missingAnnos);
return copy;
}
return typeToHierarchies.getKey();
}
Aggregations