@Nullable
  private static PyType getTypeForResolvedElement(
      @NotNull PsiElement resolved, @NotNull Context context) {
    if (context.getExpressionCache().contains(resolved)) {
      // Recursive types are not yet supported
      return null;
    }

    context.getExpressionCache().add(resolved);
    try {
      final PyType unionType = getUnionType(resolved, context);
      if (unionType != null) {
        return unionType;
      }
      final Ref<PyType> optionalType = getOptionalType(resolved, context);
      if (optionalType != null) {
        return optionalType.get();
      }
      final PyType callableType = getCallableType(resolved, context);
      if (callableType != null) {
        return callableType;
      }
      final PyType parameterizedType = getParameterizedType(resolved, context);
      if (parameterizedType != null) {
        return parameterizedType;
      }
      final PyType builtinCollection = getBuiltinCollection(resolved);
      if (builtinCollection != null) {
        return builtinCollection;
      }
      final PyType genericType = getGenericType(resolved, context);
      if (genericType != null) {
        return genericType;
      }
      final Ref<PyType> classType = getClassType(resolved, context.getTypeContext());
      if (classType != null) {
        return classType.get();
      }
      final PyType stringBasedType = getStringBasedType(resolved, context);
      if (stringBasedType != null) {
        return stringBasedType;
      }
      return null;
    } finally {
      context.getExpressionCache().remove(resolved);
    }
  }