Code review comment: Shall we add the max depth validation as well? If not there is a chance of SO for the following  ``` type ER1 error<record {| ER1 e?; |}>;  public function main() {     ER1 er1 = getER1(); }  function getER1() { return error("", e<cursor>) ```

Code under review:
private static Optional<String> getDefaultValueForType(TypeSymbol bType, int depth) {
        String typeString;

        if (bType == null) {
            return Optional.empty();
        }

        TypeSymbol rawType = getRawType(bType);
        TypeDescKind typeKind = rawType.typeKind();
        switch (typeKind) {
            case TUPLE:
                TupleTypeSymbol tupleType = (TupleTypeSymbol) rawType;
                String memberTypes = tupleType.memberTypeDescriptors().stream()
                        .map(member -> getDefaultValueForType(member, depth + 1).orElse(""))
                        .collect(Collectors.joining(", "));
                typeString = "[" + memberTypes + "]";
                break;
            case ARRAY:
                
                ArrayTypeSymbol arrayType = (ArrayTypeSymbol) rawType;
                if (arrayType.memberTypeDescriptor().typeKind() == TypeDescKind.ARRAY) {
                    typeString = "[" + getDefaultValueForType(arrayType.memberTypeDescriptor(), depth + 1).orElse("")
                            + "]";
                } else {
                    typeString = "[]";
                }
                break;
            case RECORD:
                if (depth > MAX_DEPTH) {
                    return Optional.of("{}");
                }
                
                RecordTypeSymbol recordTypeSymbol = (RecordTypeSymbol) rawType;
                typeString = "{";
                typeString += getMandatoryRecordFields(recordTypeSymbol).stream()
                        .filter(recordFieldSymbol -> recordFieldSymbol.getName().isPresent())
                        .map(recordFieldSymbol -> recordFieldSymbol.getName().get() + ": " +
                                getDefaultValueForType(recordFieldSymbol.typeDescriptor(), depth + 1).orElse(""))
                        .collect(Collectors.joining(", "));
                typeString += "}";
                break;
            case OBJECT:
                if (depth > MAX_DEPTH) {
                    return Optional.of("");
                }
                ObjectTypeSymbol objectTypeSymbol = (ObjectTypeSymbol) rawType;
                if (objectTypeSymbol.kind() == SymbolKind.CLASS) {
                    ClassSymbol classSymbol = (ClassSymbol) objectTypeSymbol;
                    if (classSymbol.initMethod().isPresent()) {
                        List<ParameterSymbol> params = classSymbol.initMethod().get().typeDescriptor().params().get();
                        String text = params.stream()
                                .map(param -> getDefaultValueForType(param.typeDescriptor(), depth + 1).orElse(""))
                                .collect(Collectors.joining(", "));
                        typeString = "new (" + text + ")";
                    } else {
                        typeString = "new ()";
                    }
                } else {
                    typeString = "object {}";
                }
                break;
            case UNION:
                if (depth > MAX_DEPTH) {
                    return Optional.of("");
                }
                List<TypeSymbol> members =
                        new ArrayList<>(((UnionTypeSymbol) rawType).memberTypeDescriptors());
                List<TypeSymbol> nilMembers = members.stream()
                        .filter(member -> member.typeKind() == TypeDescKind.NIL).collect(Collectors.toList());
                if (nilMembers.isEmpty()) {
                    typeString = getDefaultValueForType(members.get(0), depth + 1).orElse("");
                } else {
                    return Optional.of("()");
                }
                break;
            case INTERSECTION:
                TypeSymbol effectiveType = ((IntersectionTypeSymbol) rawType).effectiveTypeDescriptor();
                effectiveType = getRawType(effectiveType);
                if (effectiveType.typeKind() == TypeDescKind.INTERSECTION) {
                    
                    
                    
                    typeString = "()";
                    Optional<TypeSymbol> memberType = ((IntersectionTypeSymbol) effectiveType)
                            .memberTypeDescriptors().stream()
                            .filter(typeSymbol -> typeSymbol.typeKind() != TypeDescKind.READONLY)
                            .findAny();
                    if (memberType.isPresent()) {
                        typeString = getDefaultValueForType(memberType.get(), depth + 1).orElse("");
                    }
                } else {
                    typeString = getDefaultValueForType(effectiveType, depth + 1).orElse("");
                }
                break;
            case TABLE:
                TypeSymbol rowType = ((TableTypeSymbol) rawType).rowTypeParameter();
                typeString = "table [" + getDefaultValueForType(rowType, depth + 1).orElse("") + "]";
                break;
            case ERROR:
                TypeSymbol errorType = CommonUtil.getRawType(((ErrorTypeSymbol) rawType).detailTypeDescriptor());
                StringBuilder errorString = new StringBuilder("error (\"\"");
                if (errorType.typeKind() == TypeDescKind.RECORD) {
                    List<RecordFieldSymbol> mandatoryFields = getMandatoryRecordFields((RecordTypeSymbol) errorType);
                    if (!mandatoryFields.isEmpty()) {
                        errorString.append(", ");
                        errorString.append(mandatoryFields.stream()
                                .map(recordFieldSymbol -> recordFieldSymbol.getName().get()
                                        + " = " + getDefaultValueForType(recordFieldSymbol.typeDescriptor(), depth + 1)
                                        .orElse(""))
                                .collect(Collectors.joining(", ")));
                    }
                }
                errorString.append(")");
                typeString = errorString.toString();
                break;
            case SINGLETON:
                typeString = rawType.signature();
                break;
            case MAP:
            case FLOAT:
            case BOOLEAN:
            case STREAM:
            case XML:
            case DECIMAL:
            default:
                return getDefaultValueForTypeDescKind(typeKind);
        }

        return Optional.of(typeString);
    }

Line commented on: if (errorType.typeKind() == TypeDescKind.RECORD) {

Revised code:
private static Optional<String> getDefaultValueForType(TypeSymbol bType, int depth) {
        String typeString;

        if (bType == null) {
            return Optional.empty();
        }

        TypeSymbol rawType = getRawType(bType);
        TypeDescKind typeKind = rawType.typeKind();
        switch (typeKind) {
            case TUPLE:
                TupleTypeSymbol tupleType = (TupleTypeSymbol) rawType;
                String memberTypes = tupleType.memberTypeDescriptors().stream()
                        .map(member -> getDefaultValueForType(member, depth + 1).orElse(""))
                        .collect(Collectors.joining(", "));
                typeString = "[" + memberTypes + "]";
                break;
            case ARRAY:
                
                ArrayTypeSymbol arrayType = (ArrayTypeSymbol) rawType;
                if (arrayType.memberTypeDescriptor().typeKind() == TypeDescKind.ARRAY) {
                    typeString = "[" + getDefaultValueForType(arrayType.memberTypeDescriptor(), depth + 1).orElse("")
                            + "]";
                } else {
                    typeString = "[]";
                }
                break;
            case RECORD:
                if (depth > MAX_DEPTH) {
                    return Optional.of("{}");
                }
                
                RecordTypeSymbol recordTypeSymbol = (RecordTypeSymbol) rawType;
                typeString = "{";
                typeString += getMandatoryRecordFields(recordTypeSymbol).stream()
                        .filter(recordFieldSymbol -> recordFieldSymbol.getName().isPresent())
                        .map(recordFieldSymbol -> recordFieldSymbol.getName().get() + ": " +
                                getDefaultValueForType(recordFieldSymbol.typeDescriptor(), depth + 1).orElse(""))
                        .collect(Collectors.joining(", "));
                typeString += "}";
                break;
            case OBJECT:
                if (depth > MAX_DEPTH) {
                    return Optional.of("");
                }
                ObjectTypeSymbol objectTypeSymbol = (ObjectTypeSymbol) rawType;
                if (objectTypeSymbol.kind() == SymbolKind.CLASS) {
                    ClassSymbol classSymbol = (ClassSymbol) objectTypeSymbol;
                    if (classSymbol.initMethod().isPresent()) {
                        List<ParameterSymbol> params = classSymbol.initMethod().get().typeDescriptor().params().get();
                        String text = params.stream()
                                .map(param -> getDefaultValueForType(param.typeDescriptor(), depth + 1).orElse(""))
                                .collect(Collectors.joining(", "));
                        typeString = "new (" + text + ")";
                    } else {
                        typeString = "new ()";
                    }
                } else {
                    typeString = "object {}";
                }
                break;
            case UNION:
                if (depth > MAX_DEPTH) {
                    return Optional.of("");
                }
                List<TypeSymbol> members =
                        new ArrayList<>(((UnionTypeSymbol) rawType).memberTypeDescriptors());
                List<TypeSymbol> nilMembers = members.stream()
                        .filter(member -> member.typeKind() == TypeDescKind.NIL).collect(Collectors.toList());
                if (nilMembers.isEmpty()) {
                    typeString = getDefaultValueForType(members.get(0), depth + 1).orElse("");
                } else {
                    return Optional.of("()");
                }
                break;
            case INTERSECTION:
                TypeSymbol effectiveType = ((IntersectionTypeSymbol) rawType).effectiveTypeDescriptor();
                effectiveType = getRawType(effectiveType);
                if (effectiveType.typeKind() == TypeDescKind.INTERSECTION) {
                    
                    
                    
                    typeString = "()";
                    Optional<TypeSymbol> memberType = ((IntersectionTypeSymbol) effectiveType)
                            .memberTypeDescriptors().stream()
                            .filter(typeSymbol -> typeSymbol.typeKind() != TypeDescKind.READONLY)
                            .findAny();
                    if (memberType.isPresent()) {
                        typeString = getDefaultValueForType(memberType.get(), depth + 1).orElse("");
                    }
                } else {
                    typeString = getDefaultValueForType(effectiveType, depth + 1).orElse("");
                }
                break;
            case TABLE:
                TypeSymbol rowType = ((TableTypeSymbol) rawType).rowTypeParameter();
                typeString = "table [" + getDefaultValueForType(rowType, depth + 1).orElse("") + "]";
                break;
            case ERROR:
                TypeSymbol errorType = CommonUtil.getRawType(((ErrorTypeSymbol) rawType).detailTypeDescriptor());
                StringBuilder errorString = new StringBuilder("error (\"\"");
                if (errorType.typeKind() == TypeDescKind.RECORD && depth <= MAX_DEPTH) {
                    List<RecordFieldSymbol> mandatoryFields = getMandatoryRecordFields((RecordTypeSymbol) errorType);
                    if (!mandatoryFields.isEmpty()) {
                        errorString.append(", ");
                        errorString.append(mandatoryFields.stream()
                                .map(recordFieldSymbol -> recordFieldSymbol.getName().get()
                                        + " = " + getDefaultValueForType(recordFieldSymbol.typeDescriptor(), depth + 1)
                                        .orElse(""))
                                .collect(Collectors.joining(", ")));
                    }
                }
                errorString.append(")");
                typeString = errorString.toString();
                break;
            case SINGLETON:
                typeString = rawType.signature();
                break;
            case MAP:
            case FLOAT:
            case BOOLEAN:
            case STREAM:
            case XML:
            case DECIMAL:
            default:
                return getDefaultValueForTypeDescKind(typeKind);
        }

        return Optional.of(typeString);
    }