org.checkerframework.framework.util.typeinference.constraint.FIsAReducer Maven / Gradle / Ivy
Show all versions of checker Show documentation
package org.checkerframework.framework.util.typeinference.constraint;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedIntersectionType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedNullType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedUnionType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.framework.type.visitor.AbstractAtmComboVisitor;
import org.checkerframework.framework.util.AnnotatedTypes;
import org.plumelib.util.StringsPlume;
import java.util.List;
import java.util.Set;
import javax.lang.model.type.TypeKind;
/**
* FIsAReducer takes an FIsA constraint that is not irreducible (@see AFConstraint.isIrreducible)
* and reduces it by one step. The resulting constraint may still be reducible.
*
* Generally reductions should map to corresponding rules in
* https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.12.2.7
*/
public class FIsAReducer implements AFReducer {
protected final FIsAReducingVisitor visitor;
private final AnnotatedTypeFactory atypeFactory;
public FIsAReducer(AnnotatedTypeFactory atypeFactory) {
this.atypeFactory = atypeFactory;
this.visitor = new FIsAReducingVisitor();
}
@Override
public boolean reduce(AFConstraint constraint, Set newConstraints) {
if (constraint instanceof FIsA) {
FIsA fIsA = (FIsA) constraint;
visitor.visit(fIsA.formalParameter, fIsA.argument, newConstraints);
return true;
} else {
return false;
}
}
/**
* Given an FIsA constraint of the form: FIsA( typeFromFormalParameter, typeFromMethodArgument )
*
* FIsAReducingVisitor visits the constraint as follows: visit ( typeFromFormalParameter,
* typeFromMethodArgument, newConstraints )
*
*
The visit method will determine if the given constraint should either:
*
*
* - be discarded -- in this case, the visitor just returns
*
- reduced to a simpler constraint or set of constraints -- in this case, the new
* constraint or set of constraints is added to newConstraints
*
*
* From the JLS, in general there are 2 rules that govern F = A constraints: If F = Tj, then the
* constraint Tj = A is implied. If F = U[], where the type U involves Tj, then if A is an array
* type V[], or a type variable with an upper bound that is an array type V[], where V is a
* reference type, this algorithm is applied recursively to the constraint {@code V >> U}.
* Otherwise, no constraint is implied on Tj.
*
* Since both F and A may have component types this visitor delves into their components and
* applies these rules to the components. However, only one step is taken at a time (i.e. this
* is not a scanner)
*/
private class FIsAReducingVisitor extends AbstractAtmComboVisitor> {
@Override
public String defaultErrorMessage(
AnnotatedTypeMirror argument,
AnnotatedTypeMirror parameter,
Set afConstraints) {
return super.defaultErrorMessage(argument, parameter, afConstraints)
+ System.lineSeparator()
+ " constraints = ["
+ StringsPlume.join(", ", afConstraints)
+ "]";
}
// ------------------------------------------------------------------------
// Arrays as arguments
@Override
public Void visitArray_Array(
AnnotatedArrayType parameter,
AnnotatedArrayType argument,
Set constraints) {
constraints.add(new FIsA(parameter.getComponentType(), argument.getComponentType()));
return null;
}
@Override
public Void visitArray_Declared(
AnnotatedArrayType parameter,
AnnotatedDeclaredType argument,
Set constraints) {
return null;
}
@Override
public Void visitArray_Null(
AnnotatedArrayType parameter,
AnnotatedNullType argument,
Set constraints) {
return null;
}
@Override
public Void visitArray_Wildcard(
AnnotatedArrayType parameter,
AnnotatedWildcardType argument,
Set constraints) {
constraints.add(new FIsA(parameter, argument.getExtendsBound()));
return null;
}
// ------------------------------------------------------------------------
// Declared as argument
@Override
public Void visitDeclared_Array(
AnnotatedDeclaredType parameter,
AnnotatedArrayType argument,
Set constraints) {
// should this be Array - T[] the new A2F(String, T)
return null;
}
@Override
public Void visitDeclared_Declared(
AnnotatedDeclaredType parameter,
AnnotatedDeclaredType argument,
Set constraints) {
if (argument.isUnderlyingTypeRaw() || parameter.isUnderlyingTypeRaw()) {
return null;
}
AnnotatedDeclaredType argumentAsParam =
AnnotatedTypes.castedAsSuper(atypeFactory, argument, parameter);
if (argumentAsParam == null) {
return null;
}
List argTypeArgs = argumentAsParam.getTypeArguments();
List paramTypeArgs = parameter.getTypeArguments();
for (int i = 0; i < argTypeArgs.size(); i++) {
AnnotatedTypeMirror argTypeArg = argTypeArgs.get(i);
AnnotatedTypeMirror paramTypeArg = paramTypeArgs.get(i);
if (paramTypeArg.getKind() == TypeKind.WILDCARD) {
AnnotatedWildcardType paramWc = (AnnotatedWildcardType) paramTypeArg;
if (argTypeArg.getKind() == TypeKind.WILDCARD) {
AnnotatedWildcardType argWc = (AnnotatedWildcardType) argTypeArg;
constraints.add(
new FIsA(paramWc.getExtendsBound(), argWc.getExtendsBound()));
constraints.add(new FIsA(paramWc.getSuperBound(), argWc.getSuperBound()));
}
} else {
constraints.add(new FIsA(paramTypeArgs.get(i), argTypeArgs.get(i)));
}
}
return null;
}
@Override
public Void visitDeclared_Null(
AnnotatedDeclaredType parameter,
AnnotatedNullType argument,
Set constraints) {
return null;
}
@Override
public Void visitDeclared_Primitive(
AnnotatedDeclaredType parameter,
AnnotatedPrimitiveType argument,
Set constraints) {
return null;
}
@Override
public Void visitDeclared_Union(
AnnotatedDeclaredType parameter,
AnnotatedUnionType argument,
Set constraints) {
return null; // TODO: NOT SUPPORTED AT THE MOMENT
}
@Override
public Void visitIntersection_Intersection(
AnnotatedIntersectionType parameter,
AnnotatedIntersectionType argument,
Set constraints) {
return null; // TODO: NOT SUPPORTED AT THE MOMENT
}
@Override
public Void visitIntersection_Null(
AnnotatedIntersectionType parameter,
AnnotatedNullType argument,
Set constraints) {
return null;
}
@Override
public Void visitNull_Null(
AnnotatedNullType parameter,
AnnotatedNullType argument,
Set afConstraints) {
// we sometimes get these when we have captured type variables passed as arguments
// regardless they don't give any information
return null;
}
// ------------------------------------------------------------------------
// Primitive as argument
@Override
public Void visitPrimitive_Declared(
AnnotatedPrimitiveType parameter,
AnnotatedDeclaredType argument,
Set constraints) {
// we may be able to eliminate this case, since I believe the corresponding constraint
// will just be discarded as the parameter must be a boxed primitive
constraints.add(new FIsA(atypeFactory.getBoxedType(parameter), argument));
return null;
}
@Override
public Void visitPrimitive_Primitive(
AnnotatedPrimitiveType parameter,
AnnotatedPrimitiveType argument,
Set constraints) {
return null;
}
@Override
public Void visitTypevar_Typevar(
AnnotatedTypeVariable parameter,
AnnotatedTypeVariable argument,
Set constraints) {
// if we've reached this point and the two are corresponding type variables, then they
// are NOT ones that may have a type variable we are inferring types for and therefore
// we can discard this constraint
return null;
}
@Override
public Void visitTypevar_Null(
AnnotatedTypeVariable argument,
AnnotatedNullType parameter,
Set constraints) {
return null;
}
}
}