use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class SubtypesSolver method propagatePreviousGlbs.
/**
* /** If the target corresponding to targetRecord must be a subtype of another target for which
* we have already determined a GLB, add that target's GLB to the list of subtypes to be GLBed
* for this target.
*/
protected static void propagatePreviousGlbs(final Subtypes targetSubtypes, InferenceResult solution, final Map<AnnotatedTypeMirror, AnnotationMirrorSet> subtypesOfTarget) {
for (final Entry<TypeVariable, AnnotationMirrorSet> subtypeTarget : targetSubtypes.targets.entrySet()) {
final InferredValue subtargetInferredGlb = solution.get(subtypeTarget.getKey());
if (subtargetInferredGlb != null) {
final AnnotatedTypeMirror subtargetGlbType = ((InferredType) subtargetInferredGlb).type;
AnnotationMirrorSet subtargetAnnos = subtypesOfTarget.get(subtargetGlbType);
if (subtargetAnnos != null) {
// there is already an equivalent type in the list of subtypes, just add
// any hierarchies that are not in its list but are in the supertarget's list
subtargetAnnos.addAll(subtypeTarget.getValue());
} else {
subtypesOfTarget.put(subtargetGlbType, subtypeTarget.getValue());
}
}
}
}
use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class SubtypesSolver method glbSubtypes.
public InferenceResult glbSubtypes(final Set<TypeVariable> remainingTargets, final ConstraintMap constraints, final AnnotatedTypeFactory typeFactory) {
final InferenceResult inferenceResult = new InferenceResult();
final QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
final Types types = typeFactory.getProcessingEnv().getTypeUtils();
List<TypeVariable> targetsSubtypesLast = new ArrayList<>(remainingTargets);
// If we have two type variables <A, A extends B> order them A then B
// this is required because we will use the fact that B must be below A
// when determining the glb of B
Collections.sort(targetsSubtypesLast, new Comparator<TypeVariable>() {
@Override
public int compare(TypeVariable o1, TypeVariable o2) {
if (types.isSubtype(o1, o2)) {
return 1;
} else if (types.isSubtype(o2, o1)) {
return -1;
}
return 0;
}
});
for (final TypeVariable target : targetsSubtypesLast) {
Subtypes subtypes = constraints.getConstraints(target).subtypes;
if (subtypes.types.isEmpty()) {
continue;
}
propagatePreviousGlbs(subtypes, inferenceResult, subtypes.types);
// if the subtypes size is only 1 then we need not do any GLBing on the underlying types
// but we may have primary annotations that need to be GLBed
AnnotationMirrorMap<AnnotationMirrorSet> primaries = subtypes.primaries;
if (subtypes.types.size() == 1) {
final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> entry = subtypes.types.entrySet().iterator().next();
AnnotatedTypeMirror supertype = entry.getKey().deepCopy();
for (AnnotationMirror top : entry.getValue()) {
final AnnotationMirrorSet superAnnos = primaries.get(top);
// if it is null we're just going to use the anno already on supertype
if (superAnnos != null) {
final AnnotationMirror supertypeAnno = supertype.getAnnotationInHierarchy(top);
superAnnos.add(supertypeAnno);
}
}
if (!primaries.isEmpty()) {
for (AnnotationMirror top : qualifierHierarchy.getTopAnnotations()) {
final AnnotationMirror glb = greatestLowerBound(subtypes.primaries.get(top), qualifierHierarchy);
supertype.replaceAnnotation(glb);
}
}
inferenceResult.put(target, new InferredType(supertype));
} else {
// GLB all of the types than combine this with the GLB of primary annotation
// constraints
final AnnotatedTypeMirror glbType = GlbUtil.glbAll(subtypes.types, typeFactory);
if (glbType != null) {
if (!primaries.isEmpty()) {
for (AnnotationMirror top : qualifierHierarchy.getTopAnnotations()) {
final AnnotationMirror glb = greatestLowerBound(subtypes.primaries.get(top), qualifierHierarchy);
final AnnotationMirror currentAnno = glbType.getAnnotationInHierarchy(top);
if (currentAnno == null) {
glbType.addAnnotation(glb);
} else if (glb != null) {
glbType.replaceAnnotation(qualifierHierarchy.greatestLowerBound(glb, currentAnno));
}
}
}
inferenceResult.put(target, new InferredType(glbType));
}
}
}
return inferenceResult;
}
use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class DefaultTypeArgumentInference method clampToLowerBound.
/**
* If we have inferred a type argument from the supertype constraints and this type argument is
* BELOW the lower bound, make it AT the lower bound
*
* <p>e.g.
*
* <pre>{@code
* <@Initialized T extends @Initialized Object> void id(T t) { return t; }
* id(null);
*
* // The invocation of id will result in a type argument with primary annotations of @FBCBottom @Nullable
* // but this is below the lower bound of T in the initialization hierarchy so instead replace
* //@FBCBottom with @Initialized
*
* // This should happen ONLY with supertype constraints because raising the primary annotation would still
* // be valid for these constraints (since we just LUB the arguments involved) but would violate any
* // equality constraints
* }</pre>
*
* TODO: NOTE WE ONLY DO THIS FOR InferredType results for now but we should probably include
* targest as well
*
* @param fromArgSupertypes types inferred from LUBbing types from the arguments to the formal
* parameters
* @param targetDeclarations the declared types of the type parameters whose arguments are being
* inferred
*/
private void clampToLowerBound(InferenceResult fromArgSupertypes, List<AnnotatedTypeVariable> targetDeclarations, AnnotatedTypeFactory typeFactory) {
final QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
final AnnotationMirrorSet tops = new AnnotationMirrorSet(qualifierHierarchy.getTopAnnotations());
for (AnnotatedTypeVariable targetDecl : targetDeclarations) {
InferredValue inferred = fromArgSupertypes.get(targetDecl.getUnderlyingType());
if (inferred != null && inferred instanceof InferredType) {
final AnnotatedTypeMirror lowerBoundAsArgument = targetDecl.getLowerBound();
for (AnnotationMirror top : tops) {
final AnnotationMirror lowerBoundAnno = lowerBoundAsArgument.getEffectiveAnnotationInHierarchy(top);
final AnnotationMirror argAnno = ((InferredType) inferred).type.getEffectiveAnnotationInHierarchy(top);
if (qualifierHierarchy.isSubtype(argAnno, lowerBoundAnno)) {
((InferredType) inferred).type.replaceAnnotation(lowerBoundAnno);
}
}
}
}
}
use of org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType 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.typeinference.solver.InferredValue.InferredType in project checker-framework by typetools.
the class SupertypesSolver method mergeLubTypeWithEqualities.
/**
* We previously found a type that is equal to target but not in all hierarchies. Use the
* primary annotations from the lub type to fill in the missing annotations in this type. Use
* that type as the inferred argument.
*
* <p>If we failed to infer any annotation for a given hierarchy, either previously from
* equalities or from the lub, return null.
*/
protected InferredType mergeLubTypeWithEqualities(final TypeVariable target, final AnnotatedTypeMirror lub, final ConstraintMap constraintMap, final AnnotatedTypeFactory typeFactory) {
final Equalities equalities = constraintMap.getConstraints(target).equalities;
final AnnotationMirrorSet tops = new AnnotationMirrorSet(typeFactory.getQualifierHierarchy().getTopAnnotations());
if (!equalities.types.isEmpty()) {
// there should be only one equality type if any at this point
final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> eqEntry = equalities.types.entrySet().iterator().next();
final AnnotatedTypeMirror equalityType = eqEntry.getKey();
final AnnotationMirrorSet equalityAnnos = eqEntry.getValue();
boolean failed = false;
for (final AnnotationMirror top : tops) {
if (!equalityAnnos.contains(top)) {
final AnnotationMirror lubAnno = lub.getAnnotationInHierarchy(top);
if (lubAnno == null) {
// unannotated then "NO ANNOTATION" is the correct choice.
if (lub.getKind() == TypeKind.TYPEVAR && equalityType.getUnderlyingType().equals(lub.getUnderlyingType())) {
equalityAnnos.add(top);
} else {
failed = true;
}
} else {
equalityType.replaceAnnotation(lubAnno);
equalityAnnos.add(top);
}
}
}
if (!failed) {
return new InferredType(equalityType);
}
}
return new InferredType(lub);
}
Aggregations