Search in sources :

Example 1 with InferenceResult

use of org.checkerframework.framework.util.typeinference.solver.InferenceResult in project checker-framework by typetools.

the class DefaultTypeArgumentInference method inferFromAssignment.

/**
 * The Second half of step 6. Use the assignment context to infer a result.
 */
private InferenceResult inferFromAssignment(final AnnotatedTypeMirror assignedTo, final AnnotatedTypeMirror boxedReturnType, final AnnotatedExecutableType methodType, final Set<AFConstraint> afArgumentConstraints, final InferenceResult inferredArgs, final Set<TypeVariable> targets, final AnnotatedTypeFactory typeFactory) {
    ConstraintMap assignmentConstraints = createAssignmentConstraints(assignedTo, boxedReturnType, methodType, afArgumentConstraints, inferredArgs.toAtmMap(), targets, typeFactory);
    InferenceResult equalitiesResult = equalitiesSolver.solveEqualities(targets, assignmentConstraints, typeFactory);
    Set<TypeVariable> remainingTargets = equalitiesResult.getRemainingTargets(targets, true);
    InferenceResult subtypesResult = subtypesSolver.solveFromSubtypes(remainingTargets, assignmentConstraints, typeFactory);
    equalitiesResult.mergeSubordinate(subtypesResult);
    return equalitiesResult;
}
Also used : TypeVariable(javax.lang.model.type.TypeVariable) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) ConstraintMap(org.checkerframework.framework.util.typeinference.solver.ConstraintMap) InferenceResult(org.checkerframework.framework.util.typeinference.solver.InferenceResult)

Example 2 with InferenceResult

use of org.checkerframework.framework.util.typeinference.solver.InferenceResult in project checker-framework by typetools.

the class DefaultTypeArgumentInference method inferFromArguments.

/**
 * Step 2. Infer type arguments from the equality (TisU) and the supertype (TSuperU) constraints
 * of the methods arguments.
 */
private Pair<InferenceResult, InferenceResult> inferFromArguments(final AnnotatedTypeFactory typeFactory, final Set<AFConstraint> afArgumentConstraints, final Set<TypeVariable> targets) {
    Set<TUConstraint> tuArgConstraints = afToTuConstraints(afArgumentConstraints, targets);
    addConstraintsBetweenTargets(tuArgConstraints, targets, false, typeFactory);
    ConstraintMap argConstraints = constraintMapBuilder.build(targets, tuArgConstraints, typeFactory);
    InferenceResult inferredFromArgEqualities = equalitiesSolver.solveEqualities(targets, argConstraints, typeFactory);
    Set<TypeVariable> remainingTargets = inferredFromArgEqualities.getRemainingTargets(targets, true);
    InferenceResult fromSupertypes = supertypesSolver.solveFromSupertypes(remainingTargets, argConstraints, typeFactory);
    InferenceResult fromSubtypes = subtypesSolver.solveFromSubtypes(remainingTargets, argConstraints, typeFactory);
    fromSupertypes.mergeSubordinate(fromSubtypes);
    return Pair.of(inferredFromArgEqualities, fromSupertypes);
}
Also used : TypeVariable(javax.lang.model.type.TypeVariable) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) ConstraintMap(org.checkerframework.framework.util.typeinference.solver.ConstraintMap) InferenceResult(org.checkerframework.framework.util.typeinference.solver.InferenceResult) TUConstraint(org.checkerframework.framework.util.typeinference.constraint.TUConstraint)

Example 3 with InferenceResult

use of org.checkerframework.framework.util.typeinference.solver.InferenceResult 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 != null && equalityInferred instanceof InferredType) {
            if (supertypeInferred != null && supertypeInferred instanceof InferredType) {
                AnnotatedTypeMirror superATM = ((InferredType) supertypeInferred).type;
                AnnotatedTypeMirror equalityATM = ((InferredType) equalityInferred).type;
                if (TypesUtils.isErasedSubtype(equalityATM.getUnderlyingType(), superATM.getUnderlyingType(), typeFactory.getContext().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;
}
Also used : InferredValue(org.checkerframework.framework.util.typeinference.solver.InferredValue) InferredType(org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType) TypeVariable(javax.lang.model.type.TypeVariable) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) InferenceResult(org.checkerframework.framework.util.typeinference.solver.InferenceResult) TypeHierarchy(org.checkerframework.framework.type.TypeHierarchy) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 4 with InferenceResult

use of org.checkerframework.framework.util.typeinference.solver.InferenceResult in project checker-framework by typetools.

the class DefaultTypeArgumentInference method infer.

/**
 * This algorithm works as follows:
 *
 * <ul>
 *   <!-- ul rather than ol because of many cross-references within the text -->
 *   <li>1. Build Argument Constraints -- create a set of constraints using the arguments to the
 *       type parameter declarations, the formal parameters, and the arguments to the method
 *       call
 *   <li>2. Solve Argument Constraints -- Create two solutions from the arguments.
 *       <ol>
 *         <li>Equality Arg Solution: Solution inferred from arguments used in an invariant
 *             position (i.e. from equality constraints)
 *         <li>Supertypes Arg Solution: Solution inferred from constraints in which the
 *             parameter is a supertype of argument types. These are kept separate and merged
 *             later.
 *       </ol>
 *       Note: If there is NO assignment context we just combine the results from 2.a and 2.b,
 *       giving preference to those in 2.a, and return the result.
 *   <li>3. Build and Solve Initial Assignment Constraints -- Create a set of constraints from
 *       the assignment context WITHOUT substituting either solution from step 2.
 *   <li>4. Combine the solutions from steps 2.b and 3. This handles cases like the following:
 *       <pre>{@code
 * <T> List<T> method(T t1) {}
 * List<@Nullable String> nl = method("");
 * }</pre>
 *       If we use just the arguments to infer T we will infer @NonNull String (since the lub of
 *       all arguments would be @NonNull String). However, this would cause the assignment to
 *       fail. Instead, since {@literal @NonNull String <: @Nullable String}, we can safely
 *       infer T to be @Nullable String and both the argument types and the assignment types are
 *       compatible. In step 4, we combine the results of Step 2.b (which came from lubbing
 *       argument and argument component types) with the solution from equality constraints via
 *       the assignment context.
 *       <p>Note, we always give preference to the results inferred from method arguments if
 *       there is a conflict between the steps 2 and 4. For example:
 *       <pre>{@code
 * <T> List<T> method(T t1) {}
 * List<@NonNull String> nl = method(null);
 * }</pre>
 *       In the above example, the null argument requires that T must be @Nullable String. But
 *       the assignment context requires that the T must be @NonNull String. But, in this case
 *       if we use @NonNull String the argument "null" is invalid. In this case, we
 *       use @Nullable String and report an assignment.type.incompatible because we ALWAYS favor
 *       the arguments over the assignment context.
 *   <li>5. Combine the result from 2.a and step 4, if there is a conflict use the result from
 *       step 2.a
 *       <p>Suppose we have the following:
 *       <pre>{@code
 * <T> void method(List<@NonNull T> t, @Initialized Tt) { ... }
 * List<@FBCBottom String> lBottom = ...;
 * method( lbBottom, "nonNullString" );
 * }</pre>
 *       From the first argument we can infer that T must be exactly @FBCBottom String but we
 *       cannot infer anything for the Nullness hierarchy. For the second argument we can infer
 *       that T is at most @NonNull String but we can infer nothing in the initialization
 *       hierarchy. In this step we combine these two results, always favoring the equality
 *       constraints if there is a conflict. For the above example we would infer the following:
 *       <pre>{@code
 * T &rArr; @FBCBottom @NonNull String
 * }</pre>
 *       Another case covered in this step is:
 *       <pre>{@code
 * <T> List<T> method(List<T> t1) {}
 * List<@NonNull String> nonNullList = new ArrayList<>();
 * List<@Nullable String> nl = method(nonNullList);
 * }</pre>
 *       The above assignment should fail because T is forced to be both @NonNull and @Nullable.
 *       In cases like these, we use @NonNull String becasue we always favor constraints from
 *       the arguments over the assignment context.
 *   <li>6. Infer from Assignment Context Finally, the JLS states that we should substitute the
 *       types we have inferred up until this point back into the original argument constraints.
 *       We should then combine the constraints we get from the assignment context and solve
 *       using the greatest lower bounds of all of the constraints of the form: {@literal F :>
 *       U} (these are referred to as "subtypes" in the ConstraintMap.TargetConstraints).
 *   <li>7. Merge the result from steps 5 and 6 giving preference to 5 (the argument
 *       constraints). Return the result.
 * </ul>
 */
private Map<TypeVariable, AnnotatedTypeMirror> infer(final AnnotatedTypeFactory typeFactory, final List<AnnotatedTypeMirror> argumentTypes, final AnnotatedTypeMirror assignedTo, final ExecutableElement methodElem, final AnnotatedExecutableType methodType, final Set<TypeVariable> targets, final boolean useNullArguments) {
    // 1.  Step 1 - Build up argument constraints
    // The AFConstraints for arguments are used also in the
    Set<AFConstraint> afArgumentConstraints = createArgumentAFConstraints(typeFactory, argumentTypes, methodType, targets, useNullArguments);
    // 2. Step 2 - Solve the constraints.
    Pair<InferenceResult, InferenceResult> argInference = inferFromArguments(typeFactory, afArgumentConstraints, targets);
    // result 2.a
    final InferenceResult fromArgEqualities = argInference.first;
    // result 2.b
    final InferenceResult fromArgSubandSupers = argInference.second;
    clampToLowerBound(fromArgSubandSupers, methodType.getTypeVariables(), typeFactory);
    // a variable, assignedTo is the type of that variable
    if (assignedTo == null) {
        fromArgEqualities.mergeSubordinate(fromArgSubandSupers);
        return fromArgEqualities.toAtmMap();
    }
    // else
    final AnnotatedTypeMirror declaredReturnType = methodType.getReturnType();
    final AnnotatedTypeMirror boxedReturnType;
    if (declaredReturnType == null) {
        boxedReturnType = null;
    } else if (declaredReturnType.getKind().isPrimitive()) {
        boxedReturnType = typeFactory.getBoxedType((AnnotatedPrimitiveType) declaredReturnType);
    } else {
        boxedReturnType = declaredReturnType;
    }
    final InferenceResult fromArguments = fromArgEqualities;
    if (!((MethodSymbol) methodElem).isConstructor()) {
        // Step 3 - Infer a solution from the equality constraints in the assignment context
        InferenceResult fromAssignmentEqualities = inferFromAssignmentEqualities(assignedTo, boxedReturnType, targets, typeFactory);
        // Step 4 - Combine the results from 2.b and step 3
        InferenceResult combinedSupertypesAndAssignment = combineSupertypeAndAssignmentResults(targets, typeFactory, fromAssignmentEqualities, fromArgSubandSupers);
        // Step 5 - Combine the result from 2.a and step 4, if there is a conflict use the
        // result from step 2.a
        fromArgEqualities.mergeSubordinate(combinedSupertypesAndAssignment);
        // constraints
        if (!fromArguments.isComplete(targets)) {
            InferenceResult fromAssignment = inferFromAssignment(assignedTo, boxedReturnType, methodType, afArgumentConstraints, fromArguments, targets, typeFactory);
            // Step 7 - Merge the argument and the assignment constraints
            fromArguments.mergeSubordinate(fromAssignment);
        }
    } else {
        fromArguments.mergeSubordinate(fromArgSubandSupers);
    }
    return fromArguments.toAtmMap();
}
Also used : InferenceResult(org.checkerframework.framework.util.typeinference.solver.InferenceResult) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) AFConstraint(org.checkerframework.framework.util.typeinference.constraint.AFConstraint)

Aggregations

InferenceResult (org.checkerframework.framework.util.typeinference.solver.InferenceResult)4 TypeVariable (javax.lang.model.type.TypeVariable)3 AnnotatedTypeVariable (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable)3 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)2 ConstraintMap (org.checkerframework.framework.util.typeinference.solver.ConstraintMap)2 TypeHierarchy (org.checkerframework.framework.type.TypeHierarchy)1 AFConstraint (org.checkerframework.framework.util.typeinference.constraint.AFConstraint)1 TUConstraint (org.checkerframework.framework.util.typeinference.constraint.TUConstraint)1 InferredValue (org.checkerframework.framework.util.typeinference.solver.InferredValue)1 InferredType (org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType)1