Program: 27663
Project: 27663
Buggy source:
/** 
 * Unify   {@code this}, which may contain free type variables, with   {@code other}, a concrete type, modifying the supplied  {@code typeMultimap} to add any new template variable type bindings.
 * @return Whether unification succeeded
 */
public boolean unifyWith(JSType other,List<String> typeParameters,Multimap<String,JSType> typeMultimap){
  if (this.isUnknown()) {
    return true;
  }
 else   if (this.isTop()) {
    return other.isTop();
  }
 else   if (getMask() == TYPEVAR_MASK && typeParameters.contains(getTypeVar())) {
    updateTypemap(typeMultimap,getTypeVar(),makeType(promoteBoolean(other.getMask()),other.getObjs(),other.getTypeVar(),other.getEnums()));
    return true;
  }
 else   if (other.isTop()) {
    return false;
  }
 else   if (other.isUnknown()) {
    return true;
  }
  Set<EnumType> ununifiedEnums=null;
  if (getEnums() == null) {
    ununifiedEnums=other.getEnums();
  }
 else   if (other.getEnums() == null) {
    return false;
  }
 else {
    ununifiedEnums=new HashSet<>();
    for (    EnumType e : getEnums()) {
      if (!other.getEnums().contains(e)) {
        return false;
      }
    }
    for (    EnumType e : other.getEnums()) {
      if (!getEnums().contains(e)) {
        ununifiedEnums.add(e);
      }
    }
    if (ununifiedEnums.isEmpty()) {
      ununifiedEnums=null;
    }
  }
  Set<ObjectType> ununified=ImmutableSet.of();
  if (other.getObjs() != null) {
    ununified=new HashSet<>(other.getObjs());
  }
  if (getObjs() != null) {
    if (other.getObjs() == null) {
      return false;
    }
    for (    ObjectType targetObj : getObjs()) {
      boolean hasUnified=false;
      for (      ObjectType sourceObj : other.getObjs()) {
        if (targetObj.unifyWith(sourceObj,typeParameters,typeMultimap)) {
          ununified.remove(sourceObj);
          hasUnified=true;
        }
      }
      if (!hasUnified) {
        return false;
      }
    }
  }
  String thisTypevar=getTypeVar();
  String otherTypevar=other.getTypeVar();
  if (thisTypevar == null) {
    return otherTypevar == null && getMask() == other.getMask();
  }
 else   if (!typeParameters.contains(thisTypevar)) {
    return thisTypevar.equals(otherTypevar) && getMask() == other.getMask();
  }
 else {
    int templateMask=0;
    int thisScalarBits=getMask() & ~NON_SCALAR_MASK & ~TYPEVAR_MASK;
    int otherScalarBits=other.getMask() & ~NON_SCALAR_MASK & ~TYPEVAR_MASK;
    templateMask|=otherScalarBits & ~thisScalarBits;
    if (templateMask == BOTTOM_MASK) {
      return false;
    }
    JSType templateType=makeType(promoteBoolean(templateMask),ImmutableSet.copyOf(ununified),otherTypevar,ununifiedEnums == null ? null : ImmutableSet.copyOf(ununifiedEnums));
    updateTypemap(typeMultimap,getTypeVar(),templateType);
    return true;
  }
}

Fixed version (ground truth):
/** 
 * Unify   {@code this}, which may contain free type variables, with   {@code other}, a concrete type, modifying the supplied  {@code typeMultimap} to add any new template variable type bindings.
 * @return Whether unification succeeded
 */
public boolean unifyWith(JSType other,List<String> typeParameters,Multimap<String,JSType> typeMultimap){
  if (this.isUnknown()) {
    return true;
  }
 else   if (this.isTop()) {
    return other.isTop();
  }
 else   if (getMask() == TYPEVAR_MASK && typeParameters.contains(getTypeVar())) {
    updateTypemap(typeMultimap,getTypeVar(),makeType(promoteBoolean(other.getMask()),other.getObjs(),other.getTypeVar(),other.getEnums()));
    return true;
  }
 else   if (other.isTop()) {
    return false;
  }
 else   if (other.isUnknown()) {
    return true;
  }
  Set<EnumType> ununifiedEnums=null;
  if (getEnums() == null) {
    ununifiedEnums=other.getEnums();
  }
 else   if (other.getEnums() == null) {
    return false;
  }
 else {
    ununifiedEnums=new HashSet<>();
    for (    EnumType e : getEnums()) {
      if (!other.getEnums().contains(e)) {
        return false;
      }
    }
    for (    EnumType e : other.getEnums()) {
      if (!getEnums().contains(e)) {
        ununifiedEnums.add(e);
      }
    }
    if (ununifiedEnums.isEmpty()) {
      ununifiedEnums=null;
    }
  }
  Set<ObjectType> ununified=ImmutableSet.of();
  if (other.getObjs() != null) {
    ununified=new HashSet<>(other.getObjs());
  }
  if (getObjs() != null) {
    if (other.getObjs() == null) {
      return false;
    }
    for (    ObjectType targetObj : getObjs()) {
      boolean hasUnified=false;
      for (      ObjectType sourceObj : other.getObjs()) {
        if (targetObj.unifyWith(sourceObj,typeParameters,typeMultimap)) {
          ununified.remove(sourceObj);
          hasUnified=true;
        }
      }
      if (!hasUnified) {
        return false;
      }
    }
  }
  String thisTypevar=getTypeVar();
  String otherTypevar=other.getTypeVar();
  if (thisTypevar == null) {
    return otherTypevar == null && getMask() == other.getMask();
  }
 else   if (!typeParameters.contains(thisTypevar)) {
    return thisTypevar.equals(otherTypevar) && getMask() == other.getMask();
  }
 else {
    int templateMask=BOTTOM_MASK;
    int thisScalarBits=getMask() & ~NON_SCALAR_MASK & ~TYPEVAR_MASK;
    int otherScalarBits=other.getMask() & ~NON_SCALAR_MASK;
    templateMask|=otherScalarBits & ~thisScalarBits;
    if (templateMask == BOTTOM_MASK) {
      return false;
    }
    JSType templateType=makeType(promoteBoolean(templateMask),ImmutableSet.copyOf(ununified),otherTypevar,ununifiedEnums == null ? null : ImmutableSet.copyOf(ununifiedEnums));
    updateTypemap(typeMultimap,getTypeVar(),templateType);
    return true;
  }
}