@Nullable
  // todo: lazy
  private Pair<GrExpression, PsiType> getInstanceof() {
    final PsiElement element = getElement();
    if (element instanceof GrInstanceOfExpression) {
      GrExpression operand = ((GrInstanceOfExpression)element).getOperand();
      final GrTypeElement typeElement = ((GrInstanceOfExpression)element).getTypeElement();
      if (operand instanceof GrReferenceExpression) {
        GrExpression qualifier = ((GrReferenceExpression)operand).getQualifier();
        if ((qualifier == null || isThisRef(qualifier)) && typeElement != null) {
          return Pair.create(((GrInstanceOfExpression)element).getOperand(), typeElement.getType());
        }
      }
    }
    else if (element instanceof GrBinaryExpression && ControlFlowBuilderUtil.isInstanceOfBinary((GrBinaryExpression)element)) {
      GrExpression left = ((GrBinaryExpression)element).getLeftOperand();
      GrExpression right = ((GrBinaryExpression)element).getRightOperand();
      if (right == null) return null;
      GroovyResolveResult result = ((GrReferenceExpression)right).advancedResolve();
      final PsiElement resolved = result.getElement();
      if (resolved instanceof PsiClass) {
        PsiClassType type = JavaPsiFacade.getElementFactory(element.getProject()).createType((PsiClass)resolved, result.getSubstitutor());
        return new Pair<>(left, type);
      }
    }
    else if (element instanceof GrBinaryExpression) {
      GrExpression left = ((GrBinaryExpression)element).getLeftOperand();
      GrExpression right = ((GrBinaryExpression)element).getRightOperand();
      if (isNullLiteral(right)) {
        return Pair.create(left, PsiTypes.nullType());
      }
      else if (right != null && isNullLiteral(left)) {
        return Pair.create(right, PsiTypes.nullType());
      }
    } else if (element instanceof GrExpressionList && element.getParent() instanceof GrCaseSection &&
               element.getParent().getParent() instanceof GrSwitchElement switchElement) {
      // this branch corresponds to an arm of switch expression that is of a kind 'case Integer, String, Foo -> ...'
      GrCondition condition = switchElement.getCondition();
      if (condition instanceof GrReferenceExpression) {
        List<GrExpression> expressions = PsiUtil.getAllPatternsForCaseSection((GrCaseSection)element.getParent());
        List<PsiClass> patternClasses = ContainerUtil.mapNotNull(expressions, (GrExpression expr) -> {
          if (expr instanceof GrReferenceExpression) {
            var resolved = ((GrReferenceExpression)expr).resolve();
            if (resolved instanceof PsiClass) {
              return (PsiClass)resolved;
            }
          }
          return null;
        });
        if (patternClasses.size() != expressions.size()) {
          // something weird is in the case arm
          return null;
        }
        var classTypes = ContainerUtil.map(patternClasses, InferenceKt::type);
        PsiType commonType = TypesUtil.getLeastUpperBoundNullable(classTypes, element.getManager());
        return Pair.create((GrReferenceExpression)condition, commonType);
      }
    }
    return null;
  }
@Nullable
  // todo: lazy
  private Pair<GrExpression, PsiType> getInstanceof()