@NotNull
  private PyBlock buildSubBlock(@NotNull ASTNode child) {
    final IElementType parentType = myNode.getElementType();

    final ASTNode grandParentNode = myNode.getTreeParent();
    final IElementType grandparentType = grandParentNode == null ? null : grandParentNode.getElementType();

    final IElementType childType = child.getElementType();
    Wrap childWrap = null;
    Indent childIndent = Indent.getNoneIndent();
    Alignment childAlignment = null;

    final PyCodeStyleSettings settings = myContext.getPySettings();

    if (childType == PyElementTypes.STATEMENT_LIST) {
      if (hasLineBreaksBeforeInSameParent(child, 1) || needLineBreakInStatement()) {
        childIndent = Indent.getNormalIndent();
      }
    }
    else if (childType == PyElementTypes.CASE_CLAUSE) {
      childIndent = Indent.getNormalIndent();
    }
    else if (childType == PyElementTypes.IMPORT_ELEMENT) {
      if (parentType == PyElementTypes.FROM_IMPORT_STATEMENT) {
        childWrap = myFromImportWrapping;
      }
      else {
        childWrap = Wrap.createWrap(WrapType.NORMAL, true);
      }
      childIndent = Indent.getNormalIndent();
    }
    if (childType == PyTokenTypes.END_OF_LINE_COMMENT && (parentType == PyElementTypes.FROM_IMPORT_STATEMENT ||
                                                          parentType == PyElementTypes.MATCH_STATEMENT)) {
      childIndent = Indent.getNormalIndent();
    }

    // TODO merge it with the following check of needListAlignment()
    if (ourListElementTypes.contains(parentType)) {
      // wrapping in non-parenthesized tuple expression is not allowed (PY-1792)
      if ((parentType != PyElementTypes.TUPLE_EXPRESSION || grandparentType == PyElementTypes.PARENTHESIZED_EXPRESSION) &&
          !PyTokenTypes.ALL_BRACES.contains(childType) &&
          childType != PyTokenTypes.COMMA &&
          !isSliceOperand(child) /*&& !isSubscriptionOperand(child)*/) {
        childWrap = Wrap.createWrap(WrapType.NORMAL, true);
      }
      if (needListAlignment(child) && !myEmptySequence) {
        childAlignment = getAlignmentForChildren();
      }
      if (childType == PyTokenTypes.END_OF_LINE_COMMENT) {
        childIndent = Indent.getNormalIndent();
      }
    }

    if (parentType == PyElementTypes.BINARY_EXPRESSION) {
      if (childType != PyElementTypes.BINARY_EXPRESSION) {
        final PyBlock topmostBinary = findTopmostBinaryExpressionBlock(child);
        assert topmostBinary != null;
        final PyBlock binaryParentBlock = topmostBinary.myParent;
        final ASTNode binaryParentNode = binaryParentBlock.myNode;
        final IElementType binaryParentType = binaryParentNode.getElementType();
        // TODO check for comprehensions explicitly here
        if (ourListElementTypes.contains(binaryParentType) && needListAlignment(child) && !myEmptySequence) {
          childAlignment = binaryParentBlock.getChildAlignment();
        }
        final boolean parenthesised = binaryParentType == PyElementTypes.PARENTHESIZED_EXPRESSION;
        if (binaryParentType != PyElementTypes.RETURN_STATEMENT &&
            binaryParentType != PyElementTypes.YIELD_EXPRESSION) {
          if (childAlignment == null && topmostBinary != null &&
              !(parenthesised && isIfCondition(binaryParentNode)) &&
              !(isCondition(topmostBinary.myNode) && !ALIGN_CONDITIONS_WITHOUT_PARENTHESES)) {
            childAlignment = topmostBinary.getAlignmentForChildren();
          }
          // We omit indentation for the binary expression itself in this case (similarly to PyTupleExpression inside
          // PyParenthesisedExpression) because we indent individual operands and operators inside rather than
          // the whole contained expression.
          childIndent = parenthesised ? Indent.getContinuationIndent() : Indent.getContinuationWithoutFirstIndent();
        }
        else {
          childIndent = Indent.getNormalIndent();
        }
      }
    }
    else if (parentType == PyElementTypes.OR_PATTERN) {
      childAlignment = getAlignmentForChildren();
    }
    else if (parentType == PyElementTypes.SEQUENCE_PATTERN || parentType == PyElementTypes.MAPPING_PATTERN) {
      if (PyTokenTypes.CLOSE_BRACES.contains(childType) && !settings.HANG_CLOSING_BRACKETS ||
          PyTokenTypes.OPEN_BRACES.contains(childType)) {
        childIndent = Indent.getNoneIndent();
      }
      else {
        childIndent = Indent.getNormalIndent();
      }
    }
    else if (ourCollectionLiteralTypes.contains(parentType)) {
      if ((PyTokenTypes.CLOSE_BRACES.contains(childType) && !settings.HANG_CLOSING_BRACKETS) || 
          PyTokenTypes.OPEN_BRACES.contains(childType)) {
        childIndent = Indent.getNoneIndent();
      }
      else if (settings.USE_CONTINUATION_INDENT_FOR_COLLECTION_AND_COMPREHENSIONS) {
        childIndent = Indent.getContinuationIndent();
      }
      else {
        childIndent = Indent.getNormalIndent();
      }
    }
    else if (parentType == PyElementTypes.STRING_LITERAL_EXPRESSION) {
      if (PyTokenTypes.STRING_NODES.contains(childType) || childType == PyElementTypes.FSTRING_NODE) {
        childAlignment = getAlignmentForChildren();
      }
    }
    else if (parentType == PyElementTypes.FROM_IMPORT_STATEMENT) {
      if (myNode.findChildByType(PyTokenTypes.LPAR) != null) {
        if (childType == PyElementTypes.IMPORT_ELEMENT) {
          if (settings.ALIGN_MULTILINE_IMPORTS) {
            childAlignment = getAlignmentForChildren();
          }
          else {
            childIndent = Indent.getNormalIndent();
          }
        }
        if (childType == PyTokenTypes.RPAR) {
          childIndent = Indent.getNoneIndent();
          // Don't have hanging indent and is not going to have it due to the setting about opening parenthesis
          if (!hasHangingIndent(myNode.getPsi()) && !settings.FROM_IMPORT_NEW_LINE_AFTER_LEFT_PARENTHESIS) {
            childAlignment = getAlignmentForChildren();
          }
          else if (settings.HANG_CLOSING_BRACKETS) {
            childIndent = Indent.getNormalIndent();
          }
        }
      }
    }
    else if (isValueOfKeyValuePair(child)) {
      childIndent = Indent.getNormalIndent();
    }
    // TODO: merge with needChildAlignment()
    //Align elements vertically if there is an argument in the first line of parenthesized expression
    else if (!hasHangingIndent(myNode.getPsi()) &&
             (parentType == PyElementTypes.PARENTHESIZED_EXPRESSION ||
              (parentType == PyElementTypes.ARGUMENT_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS) ||
              (parentType == PyElementTypes.PARAMETER_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS)) &&
             !isIndentNext(child) &&
             !hasLineBreaksBeforeInSameParent(myNode.getFirstChildNode(), 1) &&
             !ourListElementTypes.contains(childType)) {

      if (!PyTokenTypes.ALL_BRACES.contains(childType)) {
        childAlignment = getAlignmentForChildren();
        childIndent = Indent.getNormalIndent();
      }
      else if (childType == PyTokenTypes.RPAR) {
        childIndent = Indent.getNoneIndent();
      }
    }
    // Note that colons are aligned together with bounds and stride
    else if (myNode.getElementType() == PyElementTypes.SLICE_ITEM) {
      childAlignment = getChildAlignment();
    }
    else if (parentType == PyElementTypes.GENERATOR_EXPRESSION || parentType == PyElementTypes.PARENTHESIZED_EXPRESSION) {
      final boolean tupleOrGenerator = parentType == PyElementTypes.GENERATOR_EXPRESSION ||
                                       myNode.getPsi(PyAstParenthesizedExpression.class).getContainedExpression() instanceof PyAstTupleExpression;
      if ((childType == PyTokenTypes.RPAR && !(tupleOrGenerator && settings.HANG_CLOSING_BRACKETS)) ||
          !hasLineBreaksBeforeInSameParent(child, 1)) {
        childIndent = Indent.getNoneIndent();
      }
      // Operands and operators of a binary expression have their own indent, no need to increase it by indenting the expression itself
      else if (childType == PyElementTypes.BINARY_EXPRESSION && parentType == PyElementTypes.PARENTHESIZED_EXPRESSION) {
        childIndent = Indent.getNoneIndent();
      }
      else {
        final boolean useWiderIndent = isIndentNext(child) || settings.USE_CONTINUATION_INDENT_FOR_COLLECTION_AND_COMPREHENSIONS;
        childIndent = useWiderIndent ? Indent.getContinuationIndent() : Indent.getNormalIndent();
      }
    }
    else if (parentType == PyElementTypes.ARGUMENT_LIST ||
             parentType == PyElementTypes.PATTERN_ARGUMENT_LIST ||
             parentType == PyElementTypes.PARAMETER_LIST) {
      if (childType == PyTokenTypes.RPAR && !settings.HANG_CLOSING_BRACKETS) {
        childIndent = Indent.getNoneIndent();
      }
      else if ((parentType == PyElementTypes.PARAMETER_LIST && settings.USE_CONTINUATION_INDENT_FOR_PARAMETERS) ||
               (parentType == PyElementTypes.ARGUMENT_LIST && settings.USE_CONTINUATION_INDENT_FOR_ARGUMENTS) ||
               argumentMayHaveSameIndentAsFollowingStatementList()) {
        childIndent = Indent.getContinuationIndent();
      }
      else {
        childIndent = Indent.getNormalIndent();
      }
    }
    else if (parentType == PyElementTypes.SUBSCRIPTION_EXPRESSION) {
      final PyAstExpression indexExpression = ((PyAstSubscriptionExpression)myNode.getPsi()).getIndexExpression();
      if (indexExpression != null && child == indexExpression.getNode()) {
        childIndent = Indent.getNormalIndent();
      }
    }
    else if (parentType == PyElementTypes.REFERENCE_EXPRESSION) {
      if (child != myNode.getFirstChildNode()) {
        childIndent = Indent.getNoneIndent();
        if (hasLineBreaksBeforeInSameParent(child, 1)) {
          if (isInControlStatement()) {
            childIndent = Indent.getContinuationIndent();
          }
          else {
            PyBlock b = myParent;
            while (b != null) {
              if (b.getNode().getPsi() instanceof PyAstParenthesizedExpression ||
                  b.getNode().getPsi() instanceof PyAstArgumentList ||
                  b.getNode().getPsi() instanceof PyAstParameterList) {
                childAlignment = getAlignmentOfChild(b, 1);
                break;
              }
              b = b.myParent;
            }
          }
        }
      }
    }
    if (childType == PyElementTypes.KEY_VALUE_EXPRESSION && isChildOfDictLiteral(child)) {
      childWrap = myDictWrapping;
    }
    if (parentType == PyElementTypes.PARAMETER_LIST &&
        childType != PyTokenTypes.COMMA &&
        childType != PyTokenTypes.LPAR &&
        childType != PyTokenTypes.RPAR) {
      childWrap = myParameterListWrapping;
    }
    if (parentType == PyElementTypes.ARGUMENT_LIST &&
        childType != PyTokenTypes.COMMA &&
        childType != PyTokenTypes.LPAR &&
        childType != PyTokenTypes.RPAR) {
      childWrap = myArgumentListWrapping;
    }

    if (isAfterStatementList(child) &&
        !hasLineBreaksBeforeInSameParent(child, 2) &&
        child.getElementType() != PyTokenTypes.END_OF_LINE_COMMENT) {
      // maybe enter was pressed and cut us from a previous (nested) statement list
      childIndent = Indent.getNormalIndent();
    }

    if (settings.DICT_ALIGNMENT == DICT_ALIGNMENT_ON_VALUE) {
      // Align not the whole value but its left bracket if it starts with it
      if (isValueOfKeyValuePairOfDictLiteral(child) && !isOpeningBracket(child.getFirstChildNode())) {
        childAlignment = myParent.myDictAlignment;
      }
      else if (isValueOfKeyValuePairOfDictLiteral(myNode) && isOpeningBracket(child)) {
        childAlignment = myParent.myParent.myDictAlignment;
      }
    }
    else if (myContext.getPySettings().DICT_ALIGNMENT == DICT_ALIGNMENT_ON_COLON) {
      if (isChildOfKeyValuePairOfDictLiteral(child) && childType == PyTokenTypes.COLON) {
        childAlignment = myParent.myDictAlignment;
      }
    }

    if (parentType == PyElementTypes.WITH_STATEMENT && isInsideWithStatementParentheses(myNode, child)) {
      if (needListAlignment(child)) {
        childAlignment = getAlignmentForChildren();
      }
      else {
        childIndent = Indent.getNormalIndent();
      }
      if (childType == PyTokenTypes.RPAR && !settings.HANG_CLOSING_BRACKETS) {
        childIndent = Indent.getNoneIndent();
      }
    }

    ASTNode prev = child.getTreePrev();
    while (prev != null && prev.getElementType() == TokenType.WHITE_SPACE) {
      if (prev.textContains('\\') &&
          !childIndent.equals(Indent.getContinuationIndent(false)) &&
          !childIndent.equals(Indent.getContinuationIndent(true))) {
        childIndent = isIndentNext(child) ? Indent.getContinuationIndent() : Indent.getNormalIndent();
        break;
      }
      prev = prev.getTreePrev();
    }

    // Don't wrap anything inside f-string fragments
    if (TreeUtil.findParent(child, PyElementTypes.FSTRING_FRAGMENT) != null) {
      childWrap = Wrap.createWrap(WrapType.NONE, false);
    }

    return new PyBlock(this, child, childAlignment, childIndent, childWrap, myContext);
  }
@NotNull
  private PyBlock buildSubBlock(@NotNull ASTNode child)