return getUnknownType();
}
// Obtain the elements in the record type. Note that the block
// above guarantees the casting to be safe
RecordType recType = ((RecordType) type);
Set<String> ownPropsNames = recType.getOwnPropertyNames();
// Fetch the information of the map function
Node mapFunction = params.get(1);
String paramKey = getFunctionParameter(mapFunction, 0);
String paramValue = getFunctionParameter(mapFunction, 1);
// The maprecord variables must not be defined in the environment
if (nameResolver.nameVars.containsKey(paramKey)) {
reportWarning(ttlAst, DUPLICATE_VARIABLE, paramKey);
return getUnknownType();
}
if (nameResolver.typeVars.containsKey(paramValue)) {
reportWarning(ttlAst, DUPLICATE_VARIABLE, paramValue);
return getUnknownType();
}
// Compute the new properties using the map function
Node mapFnBody = getFunctionBody(mapFunction);
Map<String, JSType> newProps = new HashMap<String, JSType>();
for (String propName : ownPropsNames) {
// The value of the current property
JSType propValue = recType.getSlot(propName).getType();
// Evaluate the map function body with paramValue and paramKey replaced
// by the values of the current property
NameResolver newNameResolver = new NameResolver(
addNewEntry(nameResolver.typeVars, paramValue, propValue),
addNewEntry(nameResolver.nameVars, paramKey, propName));
JSType body = evalInternal(mapFnBody, newNameResolver);
// If the body returns unknown then the whole expression returns unknown
if (body.isUnknownType()) {
return getUnknownType();
}
// Skip the property when the body evaluates to NO_TYPE
// or the empty record (Object)
if (body.isNoType() || body.isEquivalentTo(getObjectType())) {
continue;
}
// Otherwise the body must evaluate to a record type
if (!body.isRecordType()) {
reportWarning(ttlAst, MAPRECORD_BODY_INVALID, body.toString());
return getUnknownType();
}
// Add the properties of the resulting record type to the original one
RecordType bodyAsRecType = ((RecordType) body);
for (String newPropName : bodyAsRecType.getOwnPropertyNames()) {
JSType newPropValue = bodyAsRecType.getSlot(newPropName).getType();
// If the key already exists then we have to mix it with the current
// property value
putNewPropInPropertyMap(newProps, newPropName, newPropValue);
}
}