@Nullable
  public static PsiType getExpectedClosureReturnType(GrClosableBlock closure) {
    final Set<PsiType> expectedTypes = getDefaultExpectedTypes(closure);

    List<PsiType> expectedReturnTypes = new ArrayList<PsiType>();
    for (PsiType expectedType : expectedTypes) {
      if (!(expectedType instanceof PsiClassType)) return null;

      final PsiClassType.ClassResolveResult resolveResult =
          ((PsiClassType) expectedType).resolveGenerics();
      final PsiClass resolved = resolveResult.getElement();
      if (resolved == null
          || !(GroovyCommonClassNames.GROOVY_LANG_CLOSURE.equals(resolved.getQualifiedName())))
        return null;

      final PsiTypeParameter[] typeParameters = resolved.getTypeParameters();
      if (typeParameters.length != 1) return null;

      final PsiTypeParameter expected = typeParameters[0];
      final PsiType expectedReturnType = resolveResult.getSubstitutor().substitute(expected);
      if (expectedReturnType == PsiType.VOID || expectedReturnType == null) return null;

      expectedReturnTypes.add(expectedReturnType);
    }

    return TypesUtil.getLeastUpperBoundNullable(expectedReturnTypes, closure.getManager());
  }
    @Override
    public void visitSwitchStatement(GrSwitchStatement switchStatement) {
      final GrCaseSection[] sections = switchStatement.getCaseSections();
      List<PsiType> types = new ArrayList<PsiType>(sections.length);
      for (GrCaseSection section : sections) {
        final GrExpression value = section.getCaseLabel().getValue();
        final PsiType type = value != null ? value.getType() : null;
        if (type != null) types.add(type);
      }

      final PsiType upperBoundNullable =
          TypesUtil.getLeastUpperBoundNullable(types, switchStatement.getManager());
      if (upperBoundNullable == null) return;

      myResult = new TypeConstraint[] {SubtypeConstraint.create(upperBoundNullable)};
    }
        @Override
        public PsiType fun(GrAssignmentExpressionImpl assignment) {
          final GroovyResolveResult[] results = assignment.multiResolve(false);

          if (results.length == 0) {
            final GrExpression rValue = assignment.getRValue();
            return rValue == null ? null : rValue.getType();
          }

          PsiType returnType = null;
          final PsiManager manager = assignment.getManager();
          for (GroovyResolveResult result : results) {
            final PsiType substituted =
                ResolveUtil.extractReturnTypeFromCandidate(result, assignment);
            returnType = TypesUtil.getLeastUpperBoundNullable(returnType, substituted, manager);
          }
          return returnType;
        }