use of javax.lang.model.type.TypeVariable 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);
}
use of javax.lang.model.type.TypeVariable 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 Map.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 javax.lang.model.type.TypeVariable 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 Map.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 javax.lang.model.type.TypeVariable in project checker-framework by typetools.
the class AnnotatedTypeFactory method addAnnotationFromFieldInvariant.
/**
* Adds the qualifier specified by a field invariant for {@code field} to {@code type}.
*
* @param type annotated type to which the annotation is added
* @param accessedVia the annotated type of the receiver of the accessing tree. (Only used to get
* the type element of the underling type.)
* @param field element representing the field
*/
protected void addAnnotationFromFieldInvariant(AnnotatedTypeMirror type, AnnotatedTypeMirror accessedVia, VariableElement field) {
TypeMirror declaringType = accessedVia.getUnderlyingType();
// Find the first upper bound that isn't a wildcard or type variable
while (declaringType.getKind() == TypeKind.WILDCARD || declaringType.getKind() == TypeKind.TYPEVAR) {
if (declaringType.getKind() == TypeKind.WILDCARD) {
declaringType = TypesUtils.wildUpperBound(declaringType, processingEnv);
} else if (declaringType.getKind() == TypeKind.TYPEVAR) {
declaringType = ((TypeVariable) declaringType).getUpperBound();
}
}
TypeElement typeElement = TypesUtils.getTypeElement(declaringType);
if (ElementUtils.enclosingTypeElement(field).equals(typeElement)) {
// cannot be this field, even if the field has the same name.
return;
}
FieldInvariants invariants = getFieldInvariants(typeElement);
if (invariants == null) {
return;
}
List<AnnotationMirror> invariantAnnos = invariants.getQualifiersFor(field.getSimpleName());
type.replaceAnnotations(invariantAnnos);
}
use of javax.lang.model.type.TypeVariable in project checker-framework by typetools.
the class AnnotatedTypeFactory method typeVariablesFromUse.
/**
* Adapt the upper bounds of the type variables of a class relative to the type instantiation. In
* some type systems, the upper bounds depend on the instantiation of the class. For example, in
* the Generic Universe Type system, consider a class declaration
*
* <pre>{@code class C<X extends @Peer Object> }</pre>
*
* then the instantiation
*
* <pre>{@code @Rep C<@Rep Object> }</pre>
*
* is legal. The upper bounds of class C have to be adapted by the main modifier.
*
* <p>An example of an adaptation follows. Suppose, I have a declaration:
*
* <pre>{@code class MyClass<E extends List<E>>}</pre>
*
* And an instantiation:
*
* <pre>{@code new MyClass<@NonNull String>()}</pre>
*
* <p>The upper bound of E adapted to the argument String, would be {@code List<@NonNull String>}
* and the lower bound would be an AnnotatedNullType.
*
* <p>TODO: ensure that this method is consistently used instead of directly querying the type
* variables.
*
* @param type the use of the type
* @param element the corresponding element
* @return the adapted bounds of the type parameters
*/
public List<AnnotatedTypeParameterBounds> typeVariablesFromUse(AnnotatedDeclaredType type, TypeElement element) {
AnnotatedDeclaredType generic = getAnnotatedType(element);
List<AnnotatedTypeMirror> targs = type.getTypeArguments();
List<AnnotatedTypeMirror> tvars = generic.getTypeArguments();
assert targs.size() == tvars.size() : "Mismatch in type argument size between " + type + " and " + generic;
// System.err.printf("TVFU%n type: %s%n generic: %s%n", type, generic);
Map<TypeVariable, AnnotatedTypeMirror> typeParamToTypeArg = new HashMap<>();
AnnotatedDeclaredType enclosing = type;
while (enclosing != null) {
List<AnnotatedTypeMirror> enclosingTArgs = enclosing.getTypeArguments();
AnnotatedDeclaredType declaredType = getAnnotatedType((TypeElement) enclosing.getUnderlyingType().asElement());
List<AnnotatedTypeMirror> enclosingTVars = declaredType.getTypeArguments();
for (int i = 0; i < enclosingTArgs.size(); i++) {
AnnotatedTypeVariable enclosingTVar = (AnnotatedTypeVariable) enclosingTVars.get(i);
typeParamToTypeArg.put(enclosingTVar.getUnderlyingType(), enclosingTArgs.get(i));
}
enclosing = enclosing.getEnclosingType();
}
List<AnnotatedTypeParameterBounds> res = new ArrayList<>(tvars.size());
for (AnnotatedTypeMirror atm : tvars) {
AnnotatedTypeVariable atv = (AnnotatedTypeVariable) atm;
AnnotatedTypeMirror upper = typeVarSubstitutor.substitute(typeParamToTypeArg, atv.getUpperBound());
AnnotatedTypeMirror lower = typeVarSubstitutor.substitute(typeParamToTypeArg, atv.getLowerBound());
res.add(new AnnotatedTypeParameterBounds(upper, lower));
}
return res;
}
Aggregations