use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable in project checker-framework by typetools.
the class DefaultTypeArgumentInference method createAssignmentConstraints.
/**
* The first half of Step 6.
*
* <p>This method creates constraints:
*
* <ul>
* <li>between the bounds of types that are already inferred and their inferred arguments
* <li>between the assignment context and the return type of the method (with the previously
* inferred arguments substituted into these constraints)
* </ul>
*/
public ConstraintMap createAssignmentConstraints(final AnnotatedTypeMirror assignedTo, final AnnotatedTypeMirror boxedReturnType, final AnnotatedExecutableType methodType, final Set<AFConstraint> afArgumentConstraints, final Map<TypeVariable, AnnotatedTypeMirror> inferredArgs, final Set<TypeVariable> targets, final AnnotatedTypeFactory typeFactory) {
final ArrayDeque<AFConstraint> assignmentAfs = new ArrayDeque<>(2 * methodType.getTypeVariables().size() + afArgumentConstraints.size());
for (AnnotatedTypeVariable typeParam : methodType.getTypeVariables()) {
final TypeVariable target = typeParam.getUnderlyingType();
final AnnotatedTypeMirror inferredType = inferredArgs.get(target);
// the lower bound for all uninferred types Tu: Tu >> Bi and Lu >> Tu
if (inferredType != null) {
assignmentAfs.add(new A2F(inferredType, typeParam.getUpperBound()));
assignmentAfs.add(new F2A(typeParam.getLowerBound(), inferredType));
} else {
assignmentAfs.add(new F2A(typeParam, typeParam.getUpperBound()));
assignmentAfs.add(new A2F(typeParam.getLowerBound(), typeParam));
}
}
for (AFConstraint argConstraint : afArgumentConstraints) {
if (argConstraint instanceof F2A) {
assignmentAfs.add(argConstraint);
}
}
ArrayDeque<AFConstraint> substitutedAssignmentConstraints = new ArrayDeque<>(assignmentAfs.size() + 1);
for (AFConstraint afConstraint : assignmentAfs) {
substitutedAssignmentConstraints.add(afConstraint.substitute(inferredArgs));
}
final AnnotatedTypeMirror substitutedReturnType = TypeArgInferenceUtil.substitute(inferredArgs, boxedReturnType);
substitutedAssignmentConstraints.add(new F2A(substitutedReturnType, assignedTo));
final Set<AFConstraint> reducedConstraints = new LinkedHashSet<>();
reduceAfConstraints(typeFactory, reducedConstraints, substitutedAssignmentConstraints, targets);
final Set<TUConstraint> tuAssignmentConstraints = afToTuConstraints(reducedConstraints, targets);
addConstraintsBetweenTargets(tuAssignmentConstraints, targets, true, typeFactory);
return constraintMapBuilder.build(targets, tuAssignmentConstraints, typeFactory);
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable 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.type.AnnotatedTypeMirror.AnnotatedTypeVariable in project checker-framework by typetools.
the class TypeArgInferenceUtil method methodTypeToTargets.
/**
* Given an AnnotatedExecutableType return a set of type variables that represents the generic
* type parameters of that method
*/
public static Set<TypeVariable> methodTypeToTargets(final AnnotatedExecutableType methodType) {
final List<AnnotatedTypeVariable> annotatedTypeVars = methodType.getTypeVariables();
final Set<TypeVariable> targets = new LinkedHashSet<>(annotatedTypeVars.size());
for (final AnnotatedTypeVariable atv : annotatedTypeVars) {
targets.add((TypeVariable) TypeAnnotationUtils.unannotatedType(atv.getUnderlyingType()));
}
return targets;
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable in project checker-framework by typetools.
the class ConstraintMapBuilder method build.
/**
* Let Ti be a the ith target being inferred Let ATV(i) be the annotated type variable that
* represents as use of Ti which may or may not have primary annotations. Let ATM be an
* annotated type mirror that may or may not be target Tx, or have a component target Tx Let Ai
* be the type argument we are trying to infer for Ti
*
* <p>We have a set of constraints of the form: {@code ATV(i) <?> ATM}
*
* <p>Where {@code <?>} is either a subtype ({@code <:}), supertype ({@code :>}), or equality
* relationship ({@code =}).
*
* <p>Regardless of what {@code <?>} is, a constraint will only imply constraints on Ai in a
* given hierarchy if ATV(i) does NOT have a primary annotation in that hierarchy. That is:
*
* <p>E.g. Let ATV(i) be @NonNull Ti, the constraints @NonNull Ti = @NonNull @Initialized String
* does not imply any primary annotation in the Nullness hierarchy for type argument Ai because
* the Annotated type mirror has a primary annotation in the NUllness hierarchy.
*
* <p>However, it does imply that Ai has a primary annotation of @Initialized since ATV(i) has
* no primary annotation in the initialization hierarchy.
*
* <p>Note, constraints come in 2 forms:
*
* <ul>
* <li>between a target and a concrete AnnotatedTypeMirror. E.g., As seen above {@code
* (@NonNull Ti = @NonNull @Initialized String)}
* <li>between two targets E.g., {@code (@NonNull Ti = Tj)}
* </ul>
*/
public ConstraintMap build(Set<TypeVariable> targets, Set<TUConstraint> constraints, AnnotatedTypeFactory typeFactory) {
final QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
final AnnotationMirrorSet tops = new AnnotationMirrorSet(qualifierHierarchy.getTopAnnotations());
final ConstraintMap result = new ConstraintMap(targets);
final AnnotationMirrorSet tAnnos = new AnnotationMirrorSet();
final AnnotationMirrorSet uAnnos = new AnnotationMirrorSet();
final AnnotationMirrorSet hierarchiesInRelation = new AnnotationMirrorSet();
for (TUConstraint constraint : constraints) {
tAnnos.clear();
uAnnos.clear();
hierarchiesInRelation.clear();
final AnnotatedTypeVariable typeT = constraint.typeVariable;
final AnnotatedTypeMirror typeU = constraint.relatedType;
// The inferred type of T should be T.
if (!constraint.uIsArg && typeU.getKind() == TypeKind.TYPEVAR && targets.contains((TypeVariable) TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()))) {
if (typeT.getAnnotations().isEmpty() && typeU.getAnnotations().isEmpty()) {
hierarchiesInRelation.addAll(tops);
} else {
for (AnnotationMirror top : tops) {
final AnnotationMirror tAnno = typeT.getAnnotationInHierarchy(top);
final AnnotationMirror uAnno = typeU.getAnnotationInHierarchy(top);
if (tAnno == null) {
if (uAnno == null) {
hierarchiesInRelation.add(top);
} else {
tAnnos.add(uAnno);
}
} else {
if (uAnno == null) {
uAnnos.add(tAnno);
} else {
// This tells us nothing, they both should be equal but either way
// we gain no information if both type vars have annotations
}
}
}
// This case also covers the case where i = j.
if (!tAnnos.isEmpty()) {
addToPrimaryRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()), constraint, result, tAnnos, qualifierHierarchy);
}
if (!uAnnos.isEmpty()) {
addToPrimaryRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()), constraint, result, uAnnos, qualifierHierarchy);
}
}
// <?> Tj and i != j)
if (!TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()).equals(TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()))) {
addToTargetRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()), (TypeVariable) TypeAnnotationUtils.unannotatedType(typeU.getUnderlyingType()), result, constraint, hierarchiesInRelation);
}
} else {
for (AnnotationMirror top : tops) {
final AnnotationMirror tAnno = typeT.getAnnotationInHierarchy(top);
if (tAnno == null) {
hierarchiesInRelation.add(top);
}
}
addToTypeRelationship((TypeVariable) TypeAnnotationUtils.unannotatedType(typeT.getUnderlyingType()), typeU, result, constraint, hierarchiesInRelation);
}
}
return result;
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable in project checker-framework by typetools.
the class SupertypesSolver method leastUpperBound.
/**
* Successively calls least upper bound on the elements of types. Unlike
* AnnotatedTypes.leastUpperBound, this method will box primitives if necessary
*/
public static AnnotatedTypeMirror leastUpperBound(final TypeVariable target, final AnnotatedTypeFactory typeFactory, final Map<AnnotatedTypeMirror, AnnotationMirrorSet> types) {
QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
AnnotatedTypeVariable targetsDeclaredType = (AnnotatedTypeVariable) typeFactory.getAnnotatedType(target.asElement());
final AnnotationMirrorMap<AnnotationMirror> lowerBoundAnnos = TypeArgInferenceUtil.createHierarchyMap(new AnnotationMirrorSet(targetsDeclaredType.getLowerBound().getEffectiveAnnotations()), qualifierHierarchy);
final Iterator<Entry<AnnotatedTypeMirror, AnnotationMirrorSet>> typesIter = types.entrySet().iterator();
if (!typesIter.hasNext()) {
ErrorReporter.errorAbort("Calling LUB on empty list!");
}
/**
* If a constraint implies that a type parameter Ti is a supertype of an annotated type
* mirror Ai but only in a subset of all qualifier hierarchies then for all other qualifier
* hierarchies replace the primary annotation on Ai with the lowest possible annotation
* (ensuring that it won't be the LUB unless there are no other constraints, or all other
* constraints imply the bottom annotation is the LUB). Note: Even if we choose bottom as
* the lub here, the assignment context may raise this annotation.
*/
final Entry<AnnotatedTypeMirror, AnnotationMirrorSet> head = typesIter.next();
AnnotatedTypeMirror lubType = groundMissingHierarchies(head, lowerBoundAnnos);
AnnotatedTypeMirror nextType = null;
while (typesIter.hasNext()) {
nextType = groundMissingHierarchies(typesIter.next(), lowerBoundAnnos);
if (lubType.getKind().isPrimitive()) {
if (!nextType.getKind().isPrimitive()) {
lubType = typeFactory.getBoxedType((AnnotatedPrimitiveType) lubType);
}
} else if (nextType.getKind().isPrimitive()) {
if (!lubType.getKind().isPrimitive()) {
nextType = typeFactory.getBoxedType((AnnotatedPrimitiveType) nextType);
}
}
lubType = AnnotatedTypes.leastUpperBound(typeFactory, lubType, nextType);
}
return lubType;
}
Aggregations