use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class DefaultTypeArgumentInference method combineSupertypeAndAssignmentResults.
/**
* Step 4. Combine the results from using the Supertype constraints the Equality constraints from
* the assignment context.
*/
private InferenceResult combineSupertypeAndAssignmentResults(Set<TypeVariable> targets, AnnotatedTypeFactory typeFactory, InferenceResult equalityResult, InferenceResult supertypeResult) {
final TypeHierarchy typeHierarchy = typeFactory.getTypeHierarchy();
final InferenceResult result = new InferenceResult();
for (final TypeVariable target : targets) {
final InferredValue equalityInferred = equalityResult.get(target);
final InferredValue supertypeInferred = supertypeResult.get(target);
final InferredValue outputValue;
if (equalityInferred instanceof InferredType) {
if (supertypeInferred instanceof InferredType) {
AnnotatedTypeMirror superATM = ((InferredType) supertypeInferred).type;
AnnotatedTypeMirror equalityATM = ((InferredType) equalityInferred).type;
if (TypesUtils.isErasedSubtype(equalityATM.getUnderlyingType(), superATM.getUnderlyingType(), typeFactory.getChecker().getTypeUtils())) {
// If the underlying type of equalityATM is a subtype of the underlying
// type of superATM, then the call to isSubtype below will issue an error.
// So call asSuper so that the isSubtype call below works correctly.
equalityATM = AnnotatedTypes.asSuper(typeFactory, equalityATM, superATM);
}
if (typeHierarchy.isSubtype(superATM, equalityATM)) {
outputValue = equalityInferred;
} else {
outputValue = supertypeInferred;
}
} else {
outputValue = equalityInferred;
}
} else {
if (supertypeInferred != null) {
outputValue = supertypeInferred;
} else {
outputValue = null;
}
}
if (outputValue != null) {
result.put(target, outputValue);
}
}
return result;
}
use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class EqualitiesSolver method mergeConstraints.
public InferredValue mergeConstraints(final TypeVariable target, final Equalities equalities, final InferenceResult solution, ConstraintMap constraintMap, AnnotatedTypeFactory typeFactory) {
final AnnotationMirrorSet tops = new AnnotationMirrorSet(typeFactory.getQualifierHierarchy().getTopAnnotations());
InferredValue inferred = null;
if (!equalities.types.isEmpty()) {
inferred = mergeTypesAndPrimaries(equalities.types, equalities.primaries, tops, typeFactory);
}
if (inferred != null) {
return inferred;
}
// else
// We did not have enough information to infer an annotation in all hierarchies for one
// concrete type.
// However, we have a "partial solution", one in which we know the type in some but not all
// qualifier hierarchies.
// Update our set of constraints with this information
dirty |= updateTargetsWithPartiallyInferredType(equalities, constraintMap, typeFactory);
inferred = findEqualTarget(equalities, tops);
if (inferred == null && equalities.types.size() == 1) {
// Still could not find an inferred type in all hierarchies, so just use what type is known.
AnnotatedTypeMirror type = equalities.types.keySet().iterator().next();
inferred = new InferredType(type);
}
return inferred;
}
use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class EqualitiesSolver method solveEqualities.
/**
* For each target, if there is one or more equality constraints involving concrete types that
* lets us infer a primary annotation in all qualifier hierarchies then infer a concrete type
* argument. else if there is one or more equality constraints involving other targets that lets
* us infer a primary annotation in all qualifier hierarchies then infer that type argument is the
* other type argument
*
* <p>if we have inferred either a concrete type or another target as type argument rewrite all of
* the constraints for the current target to instead use the inferred type/target
*
* <p>We do this iteratively until NO new inferred type argument is found
*
* @param targets the list of type parameters for which we are inferring type arguments
* @param constraintMap the set of constraints over the set of targets
* @return a Map from target to (inferred type or target)
*/
public InferenceResult solveEqualities(Set<TypeVariable> targets, ConstraintMap constraintMap, AnnotatedTypeFactory typeFactory) {
final InferenceResult solution = new InferenceResult();
do {
dirty = false;
for (TypeVariable target : targets) {
if (solution.containsKey(target)) {
continue;
}
Equalities equalities = constraintMap.getConstraints(target).equalities;
InferredValue inferred = mergeConstraints(target, equalities, solution, constraintMap, typeFactory);
if (inferred != null) {
if (inferred instanceof InferredType) {
rewriteWithInferredType(target, ((InferredType) inferred).type, constraintMap);
} else {
rewriteWithInferredTarget(target, ((InferredTarget) inferred).target, constraintMap, typeFactory);
}
solution.put(target, inferred);
}
}
} while (dirty);
solution.resolveChainedTargets();
return solution;
}
use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class EqualitiesSolver method mergeTypesAndPrimaries.
/**
* Returns a concrete type argument or null if there was not enough information to infer one.
*
* @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, AnnotatedTypeFactory typeFactory) {
final AnnotationMirrorSet missingAnnos = new AnnotationMirrorSet(tops);
Iterator<Map.Entry<AnnotatedTypeMirror, AnnotationMirrorSet>> entryIterator = typesToHierarchies.entrySet().iterator();
if (!entryIterator.hasNext()) {
throw new BugInCF("Merging a list of empty types.");
}
final Map.Entry<AnnotatedTypeMirror, AnnotationMirrorSet> head = entryIterator.next();
AnnotatedTypeMirror mergedType = head.getKey();
missingAnnos.removeAll(head.getValue());
// AnnotatedDeclaredTypes, AnnotatedTypeVariables, and AnnotatedArrayTypes
while (entryIterator.hasNext() && !missingAnnos.isEmpty()) {
final Map.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 && typeFactory.types.isSameType(currentType.getUnderlyingType(), 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
throw new BugInCF("Missing annotation.%nmergedType=%s%ncurrentType=%s", mergedType, currentType);
}
}
}
missingAnnos.removeAll(found);
}
// add all the annotations from the primaries
for (final AnnotationMirror top : missingAnnos) {
final AnnotationMirror anno = primaries.get(top);
if (anno != null) {
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.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class InferenceResult method resolveChainedTargets.
/**
* If we had a set of inferred results, (e.g. T1 = T2, T2 = T3, T3 = String) propagate any results
* we have (the above constraints become T1 = String, T2 = String, T3 = String)
*/
public void resolveChainedTargets() {
final Map<TypeVariable, InferredValue> inferredTypes = new LinkedHashMap<>(this.size());
// TODO: we can probably make this a bit more efficient
boolean grew = true;
while (grew) {
grew = false;
for (final Map.Entry<TypeVariable, InferredValue> inferred : this.entrySet()) {
final TypeVariable target = inferred.getKey();
final InferredValue value = inferred.getValue();
if (value instanceof InferredType) {
inferredTypes.put(target, value);
} else {
final InferredTarget currentTarget = (InferredTarget) value;
final InferredType equivalentType = (InferredType) inferredTypes.get(((InferredTarget) value).target);
if (equivalentType != null) {
grew = true;
final AnnotatedTypeMirror type = equivalentType.type.deepCopy();
type.replaceAnnotations(currentTarget.additionalAnnotations);
final InferredType newConstraint = new InferredType(type);
inferredTypes.put(currentTarget.target, newConstraint);
}
}
}
}
this.putAll(inferredTypes);
}
Aggregations