# <!-- rdoc-file=error.c -->
# Class `Exception` and its subclasses are used to indicate that an error or
# other problem has occurred, and may need to be handled. See
# [Exceptions](rdoc-ref:exceptions.md).
#
# An `Exception` object carries certain information:
#
# *   The type (the exception's class), commonly StandardError, RuntimeError, or
#     a subclass of one or the other; see [Built-In Exception Class
#     Hierarchy](rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy).
# *   An optional descriptive message; see methods ::new, #message.
# *   Optional backtrace information; see methods #backtrace,
#     #backtrace_locations, #set_backtrace.
# *   An optional cause; see method #cause.
#
# ## Built-In Exception Class Hierarchy
#
# The hierarchy of built-in subclasses of class `Exception`:
#
# *   NoMemoryError
# *   ScriptError
#     *   LoadError
#     *   NotImplementedError
#     *   SyntaxError
# *   SecurityError
# *   SignalException
#     *   Interrupt
# *   StandardError
#     *   ArgumentError
#         *   UncaughtThrowError
#     *   EncodingError
#     *   FiberError
#     *   IOError
#         *   EOFError
#     *   IndexError
#         *   KeyError
#         *   StopIteration
#             *   ClosedQueueError
#     *   LocalJumpError
#     *   NameError
#         *   NoMethodError
#     *   RangeError
#         *   FloatDomainError
#     *   RegexpError
#     *   RuntimeError
#         *   FrozenError
#     *   SystemCallError
#         *   Errno (and its subclasses, representing system errors)
#     *   ThreadError
#     *   TypeError
#     *   ZeroDivisionError
# *   SystemExit
# *   SystemStackError
# *   [fatal](rdoc-ref:fatal)
#
class Exception
  # <!--
  #   rdoc-file=error.c
  #   - Exception.to_tty? -> true or false
  # -->
  # Returns `true` if exception messages will be sent to a terminal device.
  #
  def self.to_tty?: () -> bool

  # <!--
  #   rdoc-file=error.c
  #   - exception(message = nil) -> self or new_exception
  # -->
  # Returns an exception object of the same class as `self`; useful for creating a
  # similar exception, but with a different message.
  #
  # With `message` `nil`, returns `self`:
  #
  #     x0 = StandardError.new('Boom') # => #<StandardError: Boom>
  #     x1 = x0.exception              # => #<StandardError: Boom>
  #     x0.__id__ == x1.__id__         # => true
  #
  # With [string-convertible
  # object](rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects)
  # `message` (even the same as the original message), returns a new exception
  # object whose class is the same as `self`, and whose message is the given
  # `message`:
  #
  #     x1 = x0.exception('Boom') # => #<StandardError: Boom>
  #     x0..equal?(x1)            # => false
  #
  def self.exception: (?string | _ToS msg) -> instance

  # <!--
  #   rdoc-file=error.c
  #   - self == object -> true or false
  # -->
  # Returns whether `object` is the same class as `self` and its #message and
  # #backtrace are equal to those of `self`.
  #
  def ==: (untyped obj) -> bool

  # <!--
  #   rdoc-file=error.c
  #   - backtrace -> array or nil
  # -->
  # Returns the backtrace (the list of code locations that led to the exception),
  # as an array of strings.
  #
  # Example (assuming the code is stored in the file named `t.rb`):
  #
  #     def division(numerator, denominator)
  #       numerator / denominator
  #     end
  #
  #     begin
  #       division(1, 0)
  #     rescue => ex
  #       p ex.backtrace
  #       # ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
  #       loc = ex.backtrace.first
  #       p loc.class
  #       # String
  #     end
  #
  # The value returned by this method might be adjusted when raising (see
  # Kernel#raise), or during intermediate handling by #set_backtrace.
  #
  # See also #backtrace_locations that provide the same value, as structured
  # objects. (Note though that two values might not be consistent with each other
  # when backtraces are manually adjusted.)
  #
  # see [Backtraces](rdoc-ref:exceptions.md@Backtraces).
  #
  def backtrace: () -> Array[String]?

  # <!--
  #   rdoc-file=error.c
  #   - backtrace_locations -> array or nil
  # -->
  # Returns the backtrace (the list of code locations that led to the exception),
  # as an array of Thread::Backtrace::Location instances.
  #
  # Example (assuming the code is stored in the file named `t.rb`):
  #
  #     def division(numerator, denominator)
  #       numerator / denominator
  #     end
  #
  #     begin
  #       division(1, 0)
  #     rescue => ex
  #       p ex.backtrace_locations
  #       # ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
  #       loc = ex.backtrace_locations.first
  #       p loc.class
  #       # Thread::Backtrace::Location
  #       p loc.path
  #       # "t.rb"
  #       p loc.lineno
  #       # 2
  #       p loc.label
  #       # "Integer#/"
  #     end
  #
  # The value returned by this method might be adjusted when raising (see
  # Kernel#raise), or during intermediate handling by #set_backtrace.
  #
  # See also #backtrace that provide the same value as an array of strings. (Note
  # though that two values might not be consistent with each other when backtraces
  # are manually adjusted.)
  #
  # See [Backtraces](rdoc-ref:exceptions.md@Backtraces).
  #
  def backtrace_locations: () -> Array[Thread::Backtrace::Location]?

  # <!--
  #   rdoc-file=error.c
  #   - cause -> exception or nil
  # -->
  # Returns the previous value of global variable `$!`, which may be `nil` (see
  # [Global Variables](rdoc-ref:exceptions.md@Global+Variables)):
  #
  #     begin
  #       raise('Boom 0')
  #     rescue => x0
  #       puts "Exception: #{x0};  $!: #{$!};  cause: #{x0.cause.inspect}."
  #       begin
  #         raise('Boom 1')
  #       rescue => x1
  #         puts "Exception: #{x1};  $!: #{$!};  cause: #{x1.cause}."
  #         begin
  #           raise('Boom 2')
  #         rescue => x2
  #           puts "Exception: #{x2};  $!: #{$!};  cause: #{x2.cause}."
  #         end
  #       end
  #     end
  #
  # Output:
  #
  #     Exception: Boom 0;  $!: Boom 0;  cause: nil.
  #     Exception: Boom 1;  $!: Boom 1;  cause: Boom 0.
  #     Exception: Boom 2;  $!: Boom 2;  cause: Boom 1.
  #
  def cause: () -> Exception?

  # <!--
  #   rdoc-file=error.c
  #   - detailed_message(highlight: false, **kwargs) -> string
  # -->
  # Returns the message string with enhancements:
  #
  # *   Includes the exception class name in the first line.
  # *   If the value of keyword `highlight` is `true`, includes bolding and
  #     underlining ANSI codes (see below) to enhance the appearance of the
  #     message.
  #
  # Examples:
  #
  #     begin
  #       1 / 0
  #     rescue => x
  #       p x.message
  #       p x.detailed_message                  # Class name added.
  #       p x.detailed_message(highlight: true) # Class name, bolding, and underlining added.
  #     end
  #
  # Output:
  #
  #     "divided by 0"
  #     "divided by 0 (ZeroDivisionError)"
  #     "\e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m"
  #
  # This method is overridden by some gems in the Ruby standard library to add
  # information:
  #
  # *   DidYouMean::Correctable#detailed_message.
  # *   ErrorHighlight::CoreExt#detailed_message.
  # *   SyntaxSuggest#detailed_message.
  #
  # An overriding method must be tolerant of passed keyword arguments, which may
  # include (but may not be limited to):
  #
  # *   `:highlight`.
  # *   `:did_you_mean`.
  # *   `:error_highlight`.
  # *   `:syntax_suggest`.
  #
  # An overriding method should also be careful with ANSI code enhancements; see
  # [Messages](rdoc-ref:exceptions.md@Messages).
  #
  def detailed_message: (?highlight: bool?, **untyped ignored) -> String

  # <!--
  #   rdoc-file=error.c
  #   - exception(message = nil) -> self or new_exception
  # -->
  # Returns an exception object of the same class as `self`; useful for creating a
  # similar exception, but with a different message.
  #
  # With `message` `nil`, returns `self`:
  #
  #     x0 = StandardError.new('Boom') # => #<StandardError: Boom>
  #     x1 = x0.exception              # => #<StandardError: Boom>
  #     x0.__id__ == x1.__id__         # => true
  #
  # With [string-convertible
  # object](rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects)
  # `message` (even the same as the original message), returns a new exception
  # object whose class is the same as `self`, and whose message is the given
  # `message`:
  #
  #     x1 = x0.exception('Boom') # => #<StandardError: Boom>
  #     x0..equal?(x1)            # => false
  #
  def exception: (?self) -> self
               | (string | _ToS message) -> self

  # <!--
  #   rdoc-file=error.c
  #   - Exception.new(message = nil) -> exception
  # -->
  # Returns a new exception object.
  #
  # The given `message` should be a [string-convertible
  # object](rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects); see
  # method #message; if not given, the message is the class name of the new
  # instance (which may be the name of a subclass):
  #
  # Examples:
  #
  #     Exception.new         # => #<Exception: Exception>
  #     LoadError.new         # => #<LoadError: LoadError> # Subclass of Exception.
  #     Exception.new('Boom') # => #<Exception: Boom>
  #
  def initialize: (?string | _ToS message) -> void

  # <!--
  #   rdoc-file=error.c
  #   - inspect -> string
  # -->
  # Returns a string representation of `self`:
  #
  #     x = RuntimeError.new('Boom')
  #     x.inspect # => "#<RuntimeError: Boom>"
  #     x = RuntimeError.new
  #     x.inspect # => "#<RuntimeError: RuntimeError>"
  #
  def inspect: () -> String

  # <!--
  #   rdoc-file=error.c
  #   - message -> string
  # -->
  # Returns #to_s.
  #
  # See [Messages](rdoc-ref:exceptions.md@Messages).
  #
  def message: () -> String

  # <!--
  #   rdoc-file=error.c
  #   - set_backtrace(value) -> value
  # -->
  # Sets the backtrace value for `self`; returns the given `value`.
  #
  # The `value` might be:
  #
  # *   an array of Thread::Backtrace::Location;
  # *   an array of String instances;
  # *   a single String instance; or
  # *   `nil`.
  #
  # Using array of Thread::Backtrace::Location is the most consistent option: it
  # sets both #backtrace and #backtrace_locations. It should be preferred when
  # possible. The suitable array of locations can be obtained from
  # Kernel#caller_locations, copied from another error, or just set to the
  # adjusted result of the current error's #backtrace_locations:
  #
  #     require 'json'
  #
  #     def parse_payload(text)
  #       JSON.parse(text)  # test.rb, line 4
  #     rescue JSON::ParserError => ex
  #       ex.set_backtrace(ex.backtrace_locations[2...])
  #       raise
  #     end
  #
  #     parse_payload('{"wrong: "json"')
  #     # test.rb:4:in 'Object#parse_payload': unexpected token at '{"wrong: "json"' (JSON::ParserError)
  #     #
  #     # An error points to the body of parse_payload method,
  #     # hiding the parts of the backtrace related to the internals
  #     # of the "json" library
  #
  #     # The error has both #backtace and #backtrace_locations set
  #     # consistently:
  #     begin
  #       parse_payload('{"wrong: "json"')
  #     rescue => ex
  #       p ex.backtrace
  #       # ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
  #       p ex.backtrace_locations
  #       # ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
  #     end
  #
  # When the desired stack of locations is not available and should be constructed
  # from scratch, an array of strings or a singular string can be used. In this
  # case, only #backtrace is affected:
  #
  #     def parse_payload(text)
  #       JSON.parse(text)
  #     rescue JSON::ParserError => ex
  #       ex.set_backtrace(["dsl.rb:34", "framework.rb:1"])
  #       # The error have the new value in #backtrace:
  #       p ex.backtrace
  #       # ["dsl.rb:34", "framework.rb:1"]
  #
  #       # but the original one in #backtrace_locations
  #       p ex.backtrace_locations
  #       # [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
  #     end
  #
  #     parse_payload('{"wrong: "json"')
  #
  # Calling #set_backtrace with `nil` clears up #backtrace but doesn't affect
  # #backtrace_locations:
  #
  #     def parse_payload(text)
  #       JSON.parse(text)
  #     rescue JSON::ParserError => ex
  #       ex.set_backtrace(nil)
  #       p ex.backtrace
  #       # nil
  #       p ex.backtrace_locations
  #       # [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
  #     end
  #
  #     parse_payload('{"wrong: "json"')
  #
  # On reraising of such an exception, both #backtrace and #backtrace_locations is
  # set to the place of reraising:
  #
  #     def parse_payload(text)
  #       JSON.parse(text)
  #     rescue JSON::ParserError => ex
  #       ex.set_backtrace(nil)
  #       raise # test.rb, line 7
  #     end
  #
  #     begin
  #       parse_payload('{"wrong: "json"')
  #     rescue => ex
  #       p ex.backtrace
  #       # ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
  #       p ex.backtrace_locations
  #       # ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
  #     end
  #
  # See [Backtraces](rdoc-ref:exceptions.md@Backtraces).
  #
  def set_backtrace: (String | Array[String]) -> Array[String]
                   | (Array[Thread::Backtrace::Location]) -> Array[Thread::Backtrace::Location]
                   | (nil) -> nil

  # <!--
  #   rdoc-file=error.c
  #   - to_s -> string
  # -->
  # Returns a string representation of `self`:
  #
  #     x = RuntimeError.new('Boom')
  #     x.to_s # => "Boom"
  #     x = RuntimeError.new
  #     x.to_s # => "RuntimeError"
  #
  def to_s: () -> String

  # <!--
  #   rdoc-file=error.c
  #   - full_message(highlight: true, order: :top) -> string
  # -->
  # Returns an enhanced message string:
  #
  # *   Includes the exception class name.
  # *   If the value of keyword `highlight` is true (not `nil` or `false`),
  #     includes bolding ANSI codes (see below) to enhance the appearance of the
  #     message.
  # *   Includes the [backtrace](rdoc-ref:exceptions.md@Backtraces):
  #
  #     *   If the value of keyword `order` is `:top` (the default), lists the
  #         error message and the innermost backtrace entry first.
  #     *   If the value of keyword `order` is `:bottom`, lists the error message
  #         the innermost entry last.
  #
  # Example:
  #
  #     def baz
  #       begin
  #         1 / 0
  #       rescue => x
  #         pp x.message
  #         pp x.full_message(highlight: false).split("\n")
  #         pp x.full_message.split("\n")
  #       end
  #     end
  #     def bar; baz; end
  #     def foo; bar; end
  #     foo
  #
  # Output:
  #
  #     "divided by 0"
  #     ["t.rb:3:in 'Integer#/': divided by 0 (ZeroDivisionError)",
  #      "\tfrom t.rb:3:in 'Object#baz'",
  #      "\tfrom t.rb:10:in 'Object#bar'",
  #      "\tfrom t.rb:11:in 'Object#foo'",
  #      "\tfrom t.rb:12:in '<main>'"]
  #     ["t.rb:3:in 'Integer#/': \e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m",
  #      "\tfrom t.rb:3:in 'Object#baz'",
  #      "\tfrom t.rb:10:in 'Object#bar'",
  #      "\tfrom t.rb:11:in 'Object#foo'",
  #      "\tfrom t.rb:12:in '<main>'"]
  #
  # An overriding method should be careful with ANSI code enhancements; see
  # [Messages](rdoc-ref:exceptions.md@Messages).
  #
  def full_message: (?highlight: bool?, ?order: (:top | :bottom | string)?) -> String
end
