Beispiel #1
0
  /**
   * 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;
  }
  JSType getGreatestSubtypeHelper(JSType that) {
    if (that.isRecordType()) {
      RecordType thatRecord = that.toMaybeRecordType();
      RecordTypeBuilder builder = new RecordTypeBuilder(registry);
      builder.setSynthesized(true);

      // The greatest subtype consists of those *unique* properties of both
      // record types. If any property conflicts, then the NO_TYPE type
      // is returned.
      for (String property : getOwnPropertyNames()) {
        if (thatRecord.hasProperty(property)
            && !thatRecord.getPropertyType(property).isInvariant(getPropertyType(property))) {
          return registry.getNativeObjectType(JSTypeNative.NO_TYPE);
        }

        builder.addProperty(property, getPropertyType(property), getPropertyNode(property));
      }

      for (String property : thatRecord.getOwnPropertyNames()) {
        if (!hasProperty(property)) {
          builder.addProperty(
              property, thatRecord.getPropertyType(property), thatRecord.getPropertyNode(property));
        }
      }

      return builder.build();
    }

    JSType greatestSubtype = registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE);
    JSType thatRestrictedToObj =
        registry.getNativeType(JSTypeNative.OBJECT_TYPE).getGreatestSubtype(that);
    if (!thatRestrictedToObj.isEmptyType()) {
      // In this branch, the other type is some object type. We find
      // the greatest subtype with the following algorithm:
      // 1) For each property "x" of this record type, take the union
      //    of all classes with a property "x" with a compatible property type.
      //    and which are a subtype of {@code that}.
      // 2) Take the intersection of all of these unions.
      for (String propName : getOwnPropertyNames()) {
        JSType propType = getPropertyType(propName);
        UnionTypeBuilder builder = new UnionTypeBuilder(registry);
        for (ObjectType alt : registry.getEachReferenceTypeWithProperty(propName)) {
          JSType altPropType = alt.getPropertyType(propName);
          if (altPropType != null
              && !alt.isEquivalentTo(this)
              && alt.isSubtype(that)
              && propType.isInvariant(altPropType)) {
            builder.addAlternate(alt);
          }
        }
        greatestSubtype = greatestSubtype.getLeastSupertype(builder.build());
      }
    }
    return greatestSubtype;
  }
Beispiel #3
0
 public void matchRecordTypeConstraint(ObjectType constraintObj) {
   for (String prop : constraintObj.getOwnPropertyNames()) {
     JSType propType = constraintObj.getPropertyType(prop);
     if (!isPropertyTypeDeclared(prop)) {
       JSType typeToInfer = propType;
       if (!hasProperty(prop)) {
         typeToInfer = getNativeType(JSTypeNative.VOID_TYPE).getLeastSupertype(propType);
       }
       defineInferredProperty(prop, typeToInfer, null);
     }
   }
 }
Beispiel #4
0
  /**
   * Given the name of a native object property, checks whether the property is present on the
   * object and different from the native one.
   */
  private boolean hasOverridenNativeProperty(String propertyName) {
    if (isNativeObjectType()) {
      return false;
    }

    JSType propertyType = getPropertyType(propertyName);
    ObjectType nativeType =
        this.isFunctionType()
            ? registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE)
            : registry.getNativeObjectType(JSTypeNative.OBJECT_PROTOTYPE);
    JSType nativePropertyType = nativeType.getPropertyType(propertyName);
    return propertyType != nativePropertyType;
  }
  /** Determines if typeA is a subtype of typeB */
  static boolean isSubtype(ObjectType typeA, RecordType typeB) {
    // typeA is a subtype of record type typeB iff:
    // 1) typeA has all the properties declared in typeB.
    // 2) And for each property of typeB,
    //    2a) if the property of typeA is declared, it must be equal
    //        to the type of the property of typeB,
    //    2b) otherwise, it must be a subtype of the property of typeB.
    //
    // To figure out why this is true, consider the following pseudo-code:
    // /** @type {{a: (Object,null)}} */ var x;
    // /** @type {{a: !Object}} */ var y;
    // var z = {a: {}};
    // x.a = null;
    //
    // y cannot be assigned to x, because line 4 would violate y's declared
    // properties. But z can be assigned to x. Even though z and y are the
    // same type, the properties of z are inferred--and so an assignment
    // to the property of z would not violate any restrictions on it.
    for (String property : typeB.getOwnPropertyNames()) {
      if (!typeA.hasProperty(property)) {
        return false;
      }

      JSType propA = typeA.getPropertyType(property);
      JSType propB = typeB.getPropertyType(property);
      if (typeA.isPropertyTypeDeclared(property)) {
        // If one declared property isn't invariant,
        // then the whole record isn't covariant.
        if (!propA.isInvariant(propB)) {
          return false;
        }
      } else {
        // If one inferred property isn't a subtype,
        // then the whole record isn't covariant.
        if (!propA.isSubtype(propB)) {
          return false;
        }
      }
    }

    return true;
  }