@Nullable
  private static PsiType doNormalizeWildcardByPosition(
      final PsiType type, final GrExpression expression, final GrExpression toplevel) {
    if (type instanceof PsiCapturedWildcardType) {
      return doNormalizeWildcardByPosition(
          ((PsiCapturedWildcardType) type).getWildcard(), expression, toplevel);
    }

    if (type instanceof PsiWildcardType) {
      final PsiWildcardType wildcardType = (PsiWildcardType) type;

      if (PsiUtil.isAccessedForWriting(toplevel)) {
        return wildcardType.isSuper()
            ? wildcardType.getBound()
            : PsiCapturedWildcardType.create(wildcardType, expression);
      } else {
        if (wildcardType.isExtends()) {
          return wildcardType.getBound();
        } else {
          return PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope());
        }
      }
    } else if (type instanceof PsiArrayType) {
      final PsiType componentType = ((PsiArrayType) type).getComponentType();
      final PsiType normalizedComponentType =
          doNormalizeWildcardByPosition(componentType, expression, toplevel);
      if (normalizedComponentType != componentType) {
        assert normalizedComponentType != null;
        return normalizedComponentType.createArrayType();
      }
    }

    return type;
  }
  public static GrTypeComboBox createTypeComboBoxFromExpression(GrExpression expression) {
    PsiType type = expression.getType();

    if (GroovyRefactoringUtil.isDiamondNewOperator(expression)) {
      LOG.assertTrue(expression instanceof GrNewExpression);
      PsiType expected = PsiImplUtil.inferExpectedTypeForDiamond(expression);
      return createTypeComboboxFromBounds(
          type, expected, expression.getManager(), expression.getResolveScope());
    } else {
      return createTypeComboBoxWithDefType(type);
    }
  }
 @Nullable
 public static PsiType substituteBoxAndNormalizeType(
     @Nullable PsiType type,
     @NotNull PsiSubstitutor substitutor,
     @Nullable SpreadState state,
     @NotNull GrExpression expression) {
   if (type == null) return null;
   GlobalSearchScope resolveScope = expression.getResolveScope();
   PsiManager manager = expression.getManager();
   type = substitutor.substitute(type);
   type = boxPrimitiveType(type, manager, resolveScope);
   if (type == null) return null;
   type = PsiImplUtil.normalizeWildcardTypeByPosition(type, expression);
   type = SpreadState.apply(type, state, expression.getProject());
   return type;
 }
  private PsiType inferIteratorType(
      GroovyResolveResult iteratorMethodResult, GrExpression tupleInitializer) {
    PsiElement method = iteratorMethodResult.getElement();
    if (method instanceof PsiMethod) {
      return iteratorMethodResult.getSubstitutor().substitute(((PsiMethod) method).getReturnType());
    } else {
      PsiType initializerType = tupleInitializer.getType();
      PsiType iterableParam = PsiUtil.extractIterableTypeParameter(initializerType, false);

      JavaPsiFacade facade = JavaPsiFacade.getInstance(context.project);
      PsiClass iterableClass =
          facade.findClass(CommonClassNames.JAVA_UTIL_ITERATOR, tupleInitializer.getResolveScope());
      if (iterableClass != null && iterableParam != null) {
        return facade.getElementFactory().createType(iterableClass, iterableParam);
      } else {
        return facade
            .getElementFactory()
            .createTypeFromText(CommonClassNames.JAVA_UTIL_ITERATOR, tupleInitializer);
      }
    }
  }