private Property getLeftmostProp(QualifiedName qname) { String objName = qname.getLeftmostName(); Property p = props.get(objName); if (p != null) { return p; } if (nominalType != null) { return nominalType.getProp(objName); } return builtinObject == null ? null : builtinObject.getProp(objName); }
// When type is null, this method removes the property. // If the property is already declared, but isDeclared is false, be careful // to not un-declare it. // If the property is already constant, but isConstant is false, be careful // to not un-const it. private ObjectType withPropertyHelper( QualifiedName qname, JSType type, boolean isDeclared, boolean isConstant) { // TODO(blickly): If the prop exists with right type, short circuit here. PersistentMap<String, Property> newProps = this.props; if (qname.isIdentifier()) { String pname = qname.getLeftmostName(); JSType declType = getDeclaredProp(qname); if (type == null) { type = declType; } if (declType != null) { isDeclared = true; if (hasConstantProp(qname)) { isConstant = true; } if (type != null && !type.isSubtypeOf(declType)) { // Can happen in inheritance-related type errors. // Not sure what the best approach is. // For now, just forget the inferred type. type = declType; } } else if (isDeclared) { declType = type; } if (type == null && declType == null) { newProps = newProps.without(pname); } else { newProps = newProps.with( pname, isConstant ? Property.makeConstant(null, type, declType) : Property.make(type, isDeclared ? declType : null)); } } else { // This has a nested object String objName = qname.getLeftmostName(); QualifiedName objQname = new QualifiedName(objName); if (!mayHaveProp(objQname)) { Preconditions.checkState( type == null, "Trying to update property %s on type %s, but sub-property %s does" + " not exist", qname, this, objName); return this; } QualifiedName innerProps = qname.getAllButLeftmost(); Property objProp = getLeftmostProp(objQname); JSType inferred = type == null ? objProp.getType().withoutProperty(innerProps) : objProp.getType().withProperty(innerProps, type); JSType declared = objProp.getDeclaredType(); newProps = newProps.with( objName, objProp.isOptional() ? Property.makeOptional(null, inferred, declared) : Property.make(inferred, declared)); } return ObjectType.makeObjectType(nominalType, newProps, fn, isLoose, objectKind); }
boolean isPropDefinedOnSubtype(QualifiedName pname) { Preconditions.checkArgument(pname.isIdentifier()); return this.rawType.isPropDefinedOnSubtype(pname.getLeftmostName()); }