@TruffleBoundary
  public static InternalMethod lookupMethod(RubyModule module, String name) {
    CompilerAsserts.neverPartOfCompilation();

    InternalMethod method;

    // Look in the current module
    method = module.getMethods().get(name);

    if (method != null) {
      return method;
    }

    // Look in ancestors
    for (RubyModule ancestor : module.parentAncestors()) {
      method = ancestor.getMethods().get(name);

      if (method != null) {
        return method;
      }
    }

    // Nothing found

    return null;
  }
  @TruffleBoundary
  public static Map<String, InternalMethod> getAllMethods(RubyModule module) {
    CompilerAsserts.neverPartOfCompilation();

    final Map<String, InternalMethod> methods = new HashMap<>();

    // Look in the current module
    methods.putAll(module.getMethods());

    // Look in ancestors
    for (RubyModule ancestor : module.parentAncestors()) {
      for (Map.Entry<String, InternalMethod> method : ancestor.getMethods().entrySet()) {
        if (!methods.containsKey(method.getKey())) {
          methods.put(method.getKey(), method.getValue());
        }
      }
    }

    return methods;
  }
  @TruffleBoundary
  public static InternalMethod lookupSuperMethod(
      RubyModule declaringModule, String name, RubyClass objectMetaClass) {
    CompilerAsserts.neverPartOfCompilation();

    boolean foundDeclaringModule = false;
    for (RubyModule module : objectMetaClass.ancestors()) {
      if (module == declaringModule) {
        foundDeclaringModule = true;
      } else if (foundDeclaringModule) {
        InternalMethod method = module.getMethods().get(name);

        if (method != null) {
          return method;
        }
      }
    }
    assert foundDeclaringModule
        : "Did not find the declaring module in " + objectMetaClass.getName() + " ancestors";

    return null;
  }