@Override
  public JSType collapseUnion() {
    JSType currentValue = null;
    ObjectType currentCommonSuper = null;
    for (JSType a : alternatesWithoutStucturalTyping) {
      if (a.isUnknownType()) {
        return getNativeType(JSTypeNative.UNKNOWN_TYPE);
      }

      ObjectType obj = a.toObjectType();
      if (obj == null) {
        if (currentValue == null && currentCommonSuper == null) {
          // If obj is not an object, then it must be a value.
          currentValue = a;
        } else {
          // Multiple values and objects will always collapse to the ALL_TYPE.
          return getNativeType(JSTypeNative.ALL_TYPE);
        }
      } else if (currentValue != null) {
        // Values and objects will always collapse to the ALL_TYPE.
        return getNativeType(JSTypeNative.ALL_TYPE);
      } else if (currentCommonSuper == null) {
        currentCommonSuper = obj;
      } else {
        currentCommonSuper = registry.findCommonSuperObject(currentCommonSuper, obj);
      }
    }
    return currentCommonSuper;
  }
  /**
   * Computes the greatest subtype of two related templatized types.
   *
   * @return The greatest subtype.
   */
  JSType getGreatestSubtypeHelper(JSType rawThat) {
    Preconditions.checkNotNull(rawThat);

    if (!wrapsSameRawType(rawThat)) {
      if (!rawThat.isTemplatizedType()) {
        if (this.isSubtype(rawThat)) {
          return this;
        } else if (rawThat.isSubtype(this)) {
          return filterNoResolvedType(rawThat);
        }
      }
      if (this.isObject() && rawThat.isObject()) {
        return this.getNativeType(JSTypeNative.NO_OBJECT_TYPE);
      }
      return this.getNativeType(JSTypeNative.NO_TYPE);
    }

    TemplatizedType that = rawThat.toMaybeTemplatizedType();
    Preconditions.checkNotNull(that);

    if (getTemplateTypeMap()
        .checkEquivalenceHelper(
            that.getTemplateTypeMap(), EquivalenceMethod.INVARIANT, SubtypingMode.NORMAL)) {
      return this;
    }

    // For types that have the same raw type but different type parameters,
    // we simply create a type has a "unknown" type parameter.  This is
    // equivalent to the raw type.
    return getReferencedObjTypeInternal();
  }
 @Override
 public boolean setValidator(Predicate<JSType> validator) {
   for (JSType a : alternatesWithoutStucturalTyping) {
     a.setValidator(validator);
   }
   return true;
 }
  /**
   * Resolves a type by looking up its first component in the scope, and subsequent components as
   * properties. The scope must have been fully parsed and a symbol table constructed.
   *
   * @return The type of the symbol, or null if the type could not be found.
   */
  private JSType lookupViaProperties(ErrorReporter reporter, StaticTypedScope<JSType> enclosing) {
    String[] componentNames = reference.split("\\.", -1);
    if (componentNames[0].length() == 0) {
      return null;
    }
    StaticTypedSlot<JSType> slot = enclosing.getSlot(componentNames[0]);
    if (slot == null) {
      return null;
    }
    // If the first component has a type of 'Unknown', then any type
    // names using it should be regarded as silently 'Unknown' rather than be
    // noisy about it.
    JSType slotType = slot.getType();
    if (slotType == null || slotType.isAllType() || slotType.isNoType()) {
      return null;
    }
    JSType value = getTypedefType(reporter, slot);
    if (value == null) {
      return null;
    }

    // resolving component by component
    for (int i = 1; i < componentNames.length; i++) {
      ObjectType parentClass = ObjectType.cast(value);
      if (parentClass == null) {
        return null;
      }
      if (componentNames[i].length() == 0) {
        return null;
      }
      value = parentClass.getPropertyType(componentNames[i]);
    }
    return value;
  }
 @Override
 public JSType restrictByNotNullOrUndefined() {
   UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
   for (JSType t : alternatesWithoutStucturalTyping) {
     restricted.addAlternate(t.restrictByNotNullOrUndefined());
   }
   return restricted.build();
 }
 @Override
 public JSType autobox() {
   UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
   for (JSType t : alternatesWithoutStucturalTyping) {
     restricted.addAlternate(t.autobox());
   }
   return restricted.build();
 }
Exemple #7
0
 @Override
 public boolean isSubtype(JSType that) {
   if (JSType.isSubtype(this, that)) {
     return true;
   } else {
     return that.isObject() && !that.isNoType() && !that.isNoResolvedType();
   }
 }
 /**
  * A {@link UnionType} contains a given type (alternate) iff the member vector contains it.
  *
  * @param type The alternate which might be in this union.
  * @return {@code true} if the alternate is in the union
  */
 public boolean contains(JSType type) {
   for (JSType alt : alternatesWithoutStucturalTyping) {
     if (alt.isEquivalentTo(type)) {
       return true;
     }
   }
   return false;
 }
 private boolean hasAlternate(JSType type, EquivalenceMethod eqMethod, EqCache eqCache) {
   for (JSType alternate : getAlternatesWithoutStructuralTyping()) {
     if (alternate.checkEquivalenceHelper(type, eqMethod, eqCache)) {
       return true;
     }
   }
   return false;
 }
 @Override
 public String toDebugHashCodeString() {
   List<String> hashCodes = new ArrayList<>();
   for (JSType a : alternatesWithoutStucturalTyping) {
     hashCodes.add(a.toDebugHashCodeString());
   }
   return "{(" + Joiner.on(",").join(hashCodes) + ")}";
 }
 @Override
 public boolean isObject() {
   for (JSType alternate : alternatesWithoutStucturalTyping) {
     if (!alternate.isObject()) {
       return false;
     }
   }
   return true;
 }
 @Override
 public boolean hasProperty(String pname) {
   for (JSType alternate : alternatesWithoutStucturalTyping) {
     if (alternate.hasProperty(pname)) {
       return true;
     }
   }
   return false;
 }
 @Override
 public boolean isDict() {
   for (JSType typ : getAlternates()) {
     if (typ.isDict()) {
       return true;
     }
   }
   return false;
 }
 @Override
 public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) {
   // gather elements after restriction
   UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
   for (JSType element : alternatesWithoutStucturalTyping) {
     restricted.addAlternate(element.getRestrictedTypeGivenToBooleanOutcome(outcome));
   }
   return restricted.build();
 }
 /**
  * Gets the alternate types of this union type.
  *
  * @return The alternate types of this union type. The returned set is immutable.
  */
 public Collection<JSType> getAlternates() {
   for (JSType t : alternatesWithoutStucturalTyping) {
     if (t.isUnionType()) {
       rebuildAlternates();
       break;
     }
   }
   return alternates;
 }
 @Override
 public boolean canBeCalled() {
   for (JSType t : alternatesWithoutStucturalTyping) {
     if (!t.canBeCalled()) {
       return false;
     }
   }
   return true;
 }
 @Override
 public boolean isUnknownType() {
   for (JSType t : alternatesWithoutStucturalTyping) {
     if (t.isUnknownType()) {
       return true;
     }
   }
   return false;
 }
 @Override
 public boolean hasAnyTemplateTypesInternal() {
   for (JSType alternate : alternatesWithoutStucturalTyping) {
     if (alternate.hasAnyTemplateTypes()) {
       return true;
     }
   }
   return false;
 }
 /**
  * This predicate is used to test whether a given type can appear in an {@code Object} context,
  * such as the expression in a {@code with} statement.
  *
  * <p>Most types we will encounter, except notably {@code null}, have at least the potential for
  * converting to {@code Object}. Host defined objects can get peculiar.
  *
  * <p>VOID type is included here because while it is not part of the JavaScript language,
  * functions returning 'void' type can't be used as operands of any operator or statement.
  *
  * <p>
  *
  * @return {@code true} if the type is not {@link NullType} or {@link VoidType}
  */
 @Override
 public boolean matchesObjectContext() {
   // TODO(user): Reverse this logic to make it correct instead of generous.
   for (JSType t : alternatesWithoutStucturalTyping) {
     if (t.matchesObjectContext()) {
       return true;
     }
   }
   return false;
 }
 /**
  * Returns a more restricted union type than {@code this} one, in which all subtypes of {@code
  * type} have been removed.
  *
  * <p>Examples:
  *
  * <ul>
  *   <li>{@code (number,string)} restricted by {@code number} is {@code string}
  *   <li>{@code (null, EvalError, URIError)} restricted by {@code Error} is {@code null}
  * </ul>
  *
  * @param type the supertype of the types to remove from this union type
  */
 public JSType getRestrictedUnion(JSType type) {
   UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
   for (JSType t : alternatesWithoutStucturalTyping) {
     // Keep all unknown/unresolved types.
     if (t.isUnknownType() || t.isNoResolvedType() || !t.isSubtype(type)) {
       restricted.addAlternate(t);
     }
   }
   return restricted.build();
 }
 @Override
 public BooleanLiteralSet getPossibleToBooleanOutcomes() {
   BooleanLiteralSet literals = BooleanLiteralSet.EMPTY;
   for (JSType element : alternatesWithoutStucturalTyping) {
     literals = literals.union(element.getPossibleToBooleanOutcomes());
     if (literals == BooleanLiteralSet.BOTH) {
       break;
     }
   }
   return literals;
 }
 /** Gets the string representation of an optional param. */
 private void appendOptionalArgString(
     StringBuilder builder, JSType paramType, boolean forAnnotations) {
   if (paramType.isUnionType()) {
     // Remove the optionality from the var arg.
     paramType =
         paramType
             .toMaybeUnionType()
             .getRestrictedUnion(registry.getNativeType(JSTypeNative.VOID_TYPE));
   }
   builder.append(paramType.toStringHelper(forAnnotations)).append("=");
 }
 @Override
 public TernaryValue testForEquality(JSType that) {
   TernaryValue result = super.testForEquality(that);
   if (result != null) {
     return result;
   }
   if (that.isUnknownType()
       || that.isSubtype(getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) {
     return UNKNOWN;
   }
   return FALSE;
 }
  @Override
  public JSType getLeastSupertype(JSType that) {
    if (!that.isUnknownType() && !that.isUnionType()) {
      for (JSType alternate : alternatesWithoutStucturalTyping) {
        if (!alternate.isUnknownType() && that.isSubtype(alternate)) {
          return this;
        }
      }
    }

    return getLeastSupertype(this, that);
  }
  @Override
  JSType resolveInternal(ErrorReporter t, StaticTypedScope<JSType> scope) {
    setResolvedTypeInternal(this); // for circularly defined types.

    // Just resolve the alternates, but do not update as that breaks some error
    // reporting cases.
    for (JSType alternate : alternatesWithoutStucturalTyping) {
      alternate.resolve(t, scope);
    }
    // Ensure the union is in a normalized state.
    rebuildAlternates();
    return this;
  }
 @Override
 public TernaryValue testForEquality(JSType that) {
   TernaryValue result = null;
   for (JSType t : alternatesWithoutStucturalTyping) {
     TernaryValue test = t.testForEquality(that);
     if (result == null) {
       result = test;
     } else if (!result.equals(test)) {
       return UNKNOWN;
     }
   }
   return result;
 }
Exemple #27
0
  @Override
  public boolean isSubtype(JSType that) {
    if (JSType.isSubtypeHelper(this, that)) {
      return true;
    }

    // Union types
    if (that.isUnionType()) {
      // The static {@code JSType.isSubtype} check already decomposed
      // union types, so we don't need to check those again.
      return false;
    }

    // record types
    if (that.isRecordType()) {
      return RecordType.isSubtype(this, that.toMaybeRecordType());
    }

    // Interfaces
    // Find all the interfaces implemented by this class and compare each one
    // to the interface instance.
    ObjectType thatObj = that.toObjectType();
    ObjectType thatCtor = thatObj == null ? null : thatObj.getConstructor();
    if (thatCtor != null && thatCtor.isInterface()) {
      Iterable<ObjectType> thisInterfaces = getCtorImplementedInterfaces();
      for (ObjectType thisInterface : thisInterfaces) {
        if (thisInterface.isSubtype(that)) {
          return true;
        }
      }
    }

    if (getConstructor() != null && getConstructor().isInterface()) {
      for (ObjectType thisInterface : getCtorExtendedInterfaces()) {
        if (thisInterface.isSubtype(that)) {
          return true;
        }
      }
    }

    // other prototype based objects
    if (isUnknownType() || implicitPrototypeChainIsUnknown()) {
      // If unsure, say 'yes', to avoid spurious warnings.
      // TODO(user): resolve the prototype chain completely in all cases,
      // to avoid guessing.
      return true;
    }
    return this.isImplicitPrototype(thatObj);
  }
 @Override
 public TypePair getTypesUnderShallowInequality(JSType that) {
   UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
   UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
   for (JSType element : alternatesWithoutStucturalTyping) {
     TypePair p = element.getTypesUnderShallowInequality(that);
     if (p.typeA != null) {
       thisRestricted.addAlternate(p.typeA);
     }
     if (p.typeB != null) {
       thatRestricted.addAlternate(p.typeB);
     }
   }
   return new TypePair(thisRestricted.build(), thatRestricted.build());
 }
 private String getDebugHashCodeStringOf(JSType type) {
   if (type == this) {
     return "me";
   } else {
     return type.toDebugHashCodeString();
   }
 }
  @Override
  public String toDebugHashCodeString() {
    if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) {
      return super.toDebugHashCodeString();
    }

    StringBuilder b = new StringBuilder(32);
    b.append("function (");
    int paramNum = call.parameters.getChildCount();
    boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType();
    if (hasKnownTypeOfThis) {
      b.append("this:");
      b.append(getDebugHashCodeStringOf(typeOfThis));
    }
    if (paramNum > 0) {
      if (hasKnownTypeOfThis) {
        b.append(", ");
      }
      Node p = call.parameters.getFirstChild();
      b.append(getDebugHashCodeStringOf(p.getJSType()));
      p = p.getNext();
      while (p != null) {
        b.append(", ");
        b.append(getDebugHashCodeStringOf(p.getJSType()));
        p = p.getNext();
      }
    }
    b.append(")");
    b.append(": ");
    b.append(getDebugHashCodeStringOf(call.returnType));
    return b.toString();
  }