/**
  * Determine whether the given field's type is changed when type parameters from the defining
  * type's declaration are replaced with the actual type arguments from the defining type.
  *
  * @param baseField the base field
  * @param definingType the type defining the parameters and arguments to be used in the
  *     substitution
  * @return true if the type is changed by type substitution.
  */
 private static boolean isChangedByTypeSubstitution(
     FieldElement baseField, InterfaceType definingType) {
   Type[] argumentTypes = definingType.getTypeArguments();
   if (baseField != null && argumentTypes.length != 0) {
     Type baseType = baseField.getType();
     Type[] parameterTypes = definingType.getElement().getType().getTypeArguments();
     if (baseType != null) {
       Type substitutedType = baseType.substitute(argumentTypes, parameterTypes);
       if (!baseType.equals(substitutedType)) {
         return true;
       }
     }
     // If the field has a propagated type, then we need to check whether the propagated type
     // needs substitution.
     Type basePropagatedType = baseField.getPropagatedType();
     if (basePropagatedType != null) {
       Type substitutedPropagatedType =
           basePropagatedType.substitute(argumentTypes, parameterTypes);
       if (!basePropagatedType.equals(substitutedPropagatedType)) {
         return true;
       }
     }
   }
   return false;
 }
 @Override
 public FunctionTypeImpl substitute(Type[] argumentTypes, Type[] parameterTypes) {
   if (argumentTypes.length != parameterTypes.length) {
     throw new IllegalArgumentException(
         "argumentTypes.length ("
             + argumentTypes.length
             + ") != parameterTypes.length ("
             + parameterTypes.length
             + ")");
   }
   if (argumentTypes.length == 0) {
     return this;
   }
   Element element = getElement();
   FunctionTypeImpl newType =
       (element instanceof ExecutableElement)
           ? new FunctionTypeImpl((ExecutableElement) element)
           : new FunctionTypeImpl((FunctionTypeAliasElement) element);
   newType.setReturnType(returnType.substitute(argumentTypes, parameterTypes));
   newType.setNormalParameterTypes(
       substitute(normalParameterTypes, argumentTypes, parameterTypes));
   newType.setOptionalParameterTypes(
       substitute(optionalParameterTypes, argumentTypes, parameterTypes));
   newType.namedParameterTypes = substitute(namedParameterTypes, argumentTypes, parameterTypes);
   return newType;
 }