src/com/google/javascript/jscomp/TypeCheck.java
/**
   * Visits an object literal field definition <code>key : value</code>, or a class member
   * definition <code>key() { ... }</code> If the <code>lvalue</code> is a prototype modification,
   * we change the schema of the object type it is referring to.
   *
   * @param t the traversal
   * @param key the ASSIGN, STRING_KEY, MEMBER_FUNCTION_DEF, or COMPUTED_PROPERTY node
   * @param owner the parent node, either OBJECTLIT or CLASS_MEMBERS
   * @param ownerType the instance type of the enclosing object/class
   */
Visits an object literal field definition key : value, or a class member
definition key() { ... } If the lvalue is a prototype modification,
we change the schema of the object type it is referring to.

@param t the traversal
@param key the ASSIGN, STRING_KEY, MEMBER_FUNCTION_DEF, or COMPUTED_PROPERTY node
@param owner the parent node, either OBJECTLIT or CLASS_MEMBERS
@param ownerType the instance type of the enclosing object/class
Visits an object literal field definition key : value or a class member definition key () { ... } If the lvalue is a prototype modification we change the schema of the object type it is referring to . @param t the traversal @param key the ASSIGN STRING_KEY MEMBER_FUNCTION_DEF or COMPUTED_PROPERTY node @param owner the parent node either OBJECTLIT or CLASS_MEMBERS @param ownerType the instance type of the enclosing object / class
private void visitObjectOrClassLiteralKey(
      NodeTraversal t, Node key, Node owner, JSType ownerType) {
    if (key.isEmpty()) {
      return;
    }
    if (owner.isFromExterns()) {
      ensureTyped(key);
      return;
    }
    if (key.isComputedProp()) {
      validator.expectIndexMatch(t, key, ownerType, getJSType(key.getFirstChild()));
      return;
    }
    if (key.isQuotedString()) {
      if (ownerType.isStruct()) {
        report(t, key, owner.isClass() ? ILLEGAL_CLASS_KEY : ILLEGAL_OBJLIT_KEY, "struct");
      }
    } else {
      if (ownerType.isDict()
          && !(key.isMemberFunctionDef() && "constructor".equals(key.getString()))) {
        report(t, key, owner.isClass() ? ILLEGAL_CLASS_KEY : ILLEGAL_OBJLIT_KEY, "dict");
      }
    }
    Node rvalue = key.getFirstChild();
    JSType rightType = getObjectLitKeyTypeFromValueType(key, getJSType(rvalue));
    if (rightType == null) {
      rightType = getNativeType(UNKNOWN_TYPE);
    }
    JSType keyType = getJSType(key);
    JSType allowedValueType = keyType;
    if (allowedValueType.isEnumElementType()) {
      allowedValueType =
          allowedValueType.toMaybeEnumElementType().getPrimitiveType();
    }
    boolean valid = validator.expectCanAssignToPropertyOf(t, key,
        rightType, allowedValueType,
        owner, NodeUtil.getObjectLitKeyName(key));
    if (valid) {
      ensureTyped(key, rightType);
    } else {
      ensureTyped(key);
    }
    JSType objlitType = getJSType(owner);
    ObjectType type = ObjectType.cast(
        objlitType.restrictByNotNullOrUndefined());
    if (type != null) {
      String property = NodeUtil.getObjectLitKeyName(key);
      if (owner.isClass()) {
        checkPropertyInheritanceOnClassMember(t, key, property, type.toMaybeFunctionType());
      } else {
        checkPropertyInheritanceOnPrototypeLitKey(t, key, property, type);
      }
      if (type.hasProperty(property)
          && !type.isPropertyTypeInferred(property)
          && !propertyIsImplicitCast(type, property)) {
        validator.expectCanAssignToPropertyOf(
            t, key, keyType,
            type.getPropertyType(property), owner, property);
      }
    }
  }
private void visitObjectOrClassLiteralKey ( NodeTraversal t , Node key , Node owner , JSType ownerType ) { if ( key . isEmpty ( ) ) { return ; } if ( owner . isFromExterns ( ) ) { ensureTyped ( key ) ; return ; } if ( key . isComputedProp ( ) ) { validator . expectIndexMatch ( t , key , ownerType , getJSType ( key . getFirstChild ( ) ) ) ; return ; } if ( key . isQuotedString ( ) ) { if ( ownerType . isStruct ( ) ) { report ( t , key , owner . isClass ( ) ? ILLEGAL_CLASS_KEY : ILLEGAL_OBJLIT_KEY , "struct" ) ; } } else { if ( ownerType . isDict ( ) && ! ( key . isMemberFunctionDef ( ) && "constructor" . equals ( key . getString ( ) ) ) ) { report ( t , key , owner . isClass ( ) ? ILLEGAL_CLASS_KEY : ILLEGAL_OBJLIT_KEY , "dict" ) ; } } Node rvalue = key . getFirstChild ( ) ; JSType rightType = getObjectLitKeyTypeFromValueType ( key , getJSType ( rvalue ) ) ; if ( rightType == null ) { rightType = getNativeType ( UNKNOWN_TYPE ) ; } JSType keyType = getJSType ( key ) ; JSType allowedValueType = keyType ; if ( allowedValueType . isEnumElementType ( ) ) { allowedValueType = allowedValueType . toMaybeEnumElementType ( ) . getPrimitiveType ( ) ; } boolean valid = validator . expectCanAssignToPropertyOf ( t , key , rightType , allowedValueType , owner , NodeUtil . getObjectLitKeyName ( key ) ) ; if ( valid ) { ensureTyped ( key , rightType ) ; } else { ensureTyped ( key ) ; } JSType objlitType = getJSType ( owner ) ; ObjectType type = ObjectType . cast ( objlitType . restrictByNotNullOrUndefined ( ) ) ; if ( type != null ) { String property = NodeUtil . getObjectLitKeyName ( key ) ; if ( owner . isClass ( ) ) { checkPropertyInheritanceOnClassMember ( t , key , property , type . toMaybeFunctionType ( ) ) ; } else { checkPropertyInheritanceOnPrototypeLitKey ( t , key , property , type ) ; } if ( type . hasProperty ( property ) && ! type . isPropertyTypeInferred ( property ) && ! propertyIsImplicitCast ( type , property ) ) { validator . expectCanAssignToPropertyOf ( t , key , keyType , type . getPropertyType ( property ) , owner , property ) ; } } }
Visits an object literal field definition <code>key : value</code>, or a class member
 definition <code>key() { ... }</code> If the <code>lvalue</code> is a prototype modification,
 we change the schema of the object type it is referring to.
Visits an object literal field definition <code > key : value< / code > or a class member definition <code > key () { ... } < / code > If the <code > lvalue< / code > is a prototype modification we change the schema of the object type it is referring to .
// Semicolons in a CLASS_MEMBERS body will produce EMPTY nodes: skip them. // Do not validate object lit value types in externs. We don't really care, // and it makes it easier to generate externs. // Validate computed properties similarly to how we validate GETELEMs. // NB: this case will never be triggered for member functions, since we store quoted // member functions as computed properties. This case does apply to regular string key // properties, getters, and setters. // See also https://github.com/google/closure-compiler/issues/3071 // we have either a non-quoted string or a member function def // Neither is allowed for an @dict type except for "constructor" as a special case. // Object literals annotated as @dict may only have // If you annotate a class with @dict, only the constructor can be a non-computed property. // TODO(johnlenz): Validate get and set function declarations are valid // as is the functions can have "extraneous" bits. // For getter and setter property definitions the // r-value type != the property type. // Validate value is assignable to the key type. // Validate that the key type is assignable to the object property type. // This is necessary as the owner may have been cast to a non-literal // object type. // TODO(johnlenz): consider introducing a CAST node to the AST (or // perhaps a parentheses node). // TODO(lharker): add a unit test for the following if case or remove it. // Removing the check doesn't break any unit tests, but it does have coverage in // our coverage report.