/**
  * Given a partial solution to our type argument inference, replace any uses of type parameters
  * that have been solved with their arguments.
  *
  * <p>That is: Let S be a partial solution to our inference (i.e. we have inferred type arguments
  * for some types) Let S be a map {@code (T0 -> A0, T1 -> A1, ..., TN -> AN)} where Ti is a type
  * parameter and Ai is its solved argument. For all uses of Ti in this constraint, replace them
  * with Ai.
  *
  * <p>For the mapping {@code (T0 -> A0)}, the following constraint: {@code ArrayList<T0> <<
  * List<T1>}
  *
  * <p>Becomes: {@code ArrayList<A0> << List<T1>}
  *
  * <p>A constraint: {@code T0 << T1}
  *
  * <p>Becomes: {@code A0 << T1}
  *
  * @param substitutions a mapping of target type parameter to the type argument to
  * @return a new constraint that contains no use of the keys in substitutions
  */
 public AFConstraint substitute(final Map<TypeVariable, AnnotatedTypeMirror> substitutions) {
   final AnnotatedTypeMirror newArgument =
       TypeArgInferenceUtil.substitute(substitutions, argument);
   final AnnotatedTypeMirror newFormalParameter =
       TypeArgInferenceUtil.substitute(substitutions, formalParameter);
   return construct(newArgument, newFormalParameter);
 }