All Downloads are FREE. Search and download functionalities are using the official Maven repository.

framework.src.org.checkerframework.framework.util.typeinference.solver.InferenceResult Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.framework.util.typeinference.solver;

import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredTarget;
import org.checkerframework.framework.util.typeinference.solver.InferredValue.InferredType;

import javax.lang.model.type.TypeVariable;
import java.util.*;
import java.util.Map.Entry;

/**
 * Represents the result from inferring type arguments.
 * InferenceResult is a map from: ({@code Target type variable -> inferred type or target})
 */
public class InferenceResult extends LinkedHashMap {
    private static final long serialVersionUID = 6911459752070485818L;

    /**
     * @return the set of targets that still don't have an inferred argument
     */
    public Set getRemainingTargets(final Set allTargets, boolean inferredTypesOnly) {
        final LinkedHashSet remainingTargets = new LinkedHashSet<>(allTargets);

        if (inferredTypesOnly) {

            for (TypeVariable target : keySet()) {
                if (this.get(target) instanceof InferredType) {
                    remainingTargets.remove(target);
                }

            }

        } else {
            remainingTargets.removeAll(this.keySet());
        }

        return remainingTargets;
    }

    /**
     * @return true if we have inferred a concrete type for all targets
     */
    public boolean isComplete(final Set targets) {
        for (final TypeVariable target : targets) {
            final InferredValue inferred = this.get(target);

            if (inferred == null || inferred instanceof InferredTarget) {
                return false;
            }
        }
        return this.keySet().containsAll(targets);
    }

    /**
     * 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 inferredTypes = new LinkedHashMap<>(this.size());

        //TODO: we can probably make this a bit more efficient
        boolean grew = true;
        while (grew == true) {
            grew = false;
            for (final Entry 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);
    }

    public Map toAtmMap() {
        final Map result = new LinkedHashMap<>(this.size());
        for (final Entry entry : this.entrySet()) {
            final InferredValue inferredValue = entry.getValue();
            if (inferredValue instanceof InferredType) {
                result.put(entry.getKey(), ((InferredType) inferredValue).type);
            }
        }

        return result;
    }

    /**
     * Merges values in subordinate into this result, keeping the results form any
     * type arguments that were already contained by this InferenceResult
     * @param subordinate a result which we wish to merge into this result
     */
    public void mergeSubordinate(final InferenceResult subordinate) {
        final LinkedHashSet previousKeySet = new LinkedHashSet<>(this.keySet());
        final LinkedHashSet remainingSubKeys = new LinkedHashSet<>(subordinate.keySet());
        remainingSubKeys.removeAll(keySet());

        for (TypeVariable target : previousKeySet) {
            mergeTarget(target, subordinate);
        }


        for (TypeVariable target : remainingSubKeys) {
            this.put(target, subordinate.get(target));
        }

        resolveChainedTargets();
    }

    /**
     * Performs a merge for a specific target, we keep only results that lead to a concrete type
     */
    protected InferredType mergeTarget(final TypeVariable target, final InferenceResult subordinate) {
        final InferredValue inferred = this.get(target);
        if (inferred instanceof InferredTarget) {
            InferredType newType = mergeTarget(((InferredTarget) inferred).target, subordinate);

            if (newType == null) {
                final InferredValue subValue = subordinate.get(target);
                if (subValue != null && subValue instanceof InferredType) {
                    this.put(target, subValue);
                    return newType;
                }
            } else {
                this.put(target, newType);
                return newType;
            }

            return null;
        } // else

        return (InferredType) inferred;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy