<commit_before>my class Failure is Nil {
    has $.exception;
    has $.backtrace;
#?if !jvm
    has int $!handled;
#?endif
#?if jvm
    has Int $!handled;   # alas, native int breaks on the JVM
#?endif

    method !SET-SELF($!exception) {
        $!backtrace = $!exception.backtrace || Backtrace.new(5);
        $!exception.reset-backtrace;
        self
    }

    multi method new(Failure:D:) { self!throw }
    multi method new(Failure:U:) {
        my $stash := CALLER::;
        my $payload = $stash<$!>.DEFINITE ?? $stash<$!> !! "Failed";
        nqp::create(self)!SET-SELF(
          $payload ~~ Exception ?? $payload !! X::AdHoc.new(:$payload)
        )
    }
    multi method new(Failure:U: Exception:D \exception) {
        nqp::create(self)!SET-SELF(exception)
    }
    multi method new(Failure:U: $payload) {
        nqp::create(self)!SET-SELF(X::AdHoc.new(:$payload))
    }
    multi method new(Failure:U: |cap (*@msg)) {
        nqp::create(self)!SET-SELF(X::AdHoc.from-slurpy(|cap))
    }

    submethod DESTROY () {
        note "WARNING: unhandled Failure detected in DESTROY. If you meant "
            ~ "to ignore it, you can mark it as handled by calling .Bool, "
            ~ ".so, .not, or .defined methods. The Failure was:\n" ~ self.mess
        unless $!handled;
    }

    # allow Failures to throw when they replace an Iterable
    multi method iterator(Failure:D:) { self!throw }
    multi method list(Failure:D:)     { self!throw }

    # Marks the Failure has handled (since we're now fatalizing it) and throws.
    method !throw(Failure:D:) {
        $!handled = 1;
        $!exception.throw($!backtrace);
    }

    # Turns out multidimensional lookups are one way to leak unhandled failures, so
    # we'll just propagate the initial failure much as we propagate Nil on methods.
    method AT-POS(|) { self }
    method AT-KEY(|) { self }

    multi method defined(Failure:D: --> False) { $!handled = 1 }

    multi method Bool(Failure:D: --> False) { $!handled = 1 }
    method handled() is rw {
        Proxy.new(
          FETCH => {
#?if !jvm
              nqp::hllbool($!handled)
#?endif
#?if jvm
              $!handled.Bool
#?endif
          },
          STORE => -> $, $value { $!handled = $value.Bool.Numeric }
       )
    }

    method Capture() {
        self.DEFINITE.not || $!handled
            ?? X::Cannot::Capture.new(what => self).throw
            !! self!throw
    }
    method Int(Failure:D:)        { $!handled ?? Int !! self!throw(); }
    method Num(Failure:D:)        { $!handled ?? NaN !! self!throw(); }
    method Numeric(Failure:D:)    { $!handled ?? NaN !! self!throw(); }

    method Set(Failure:D:)     { $!handled ?? Set.new(self)     !! self!throw }
    method SetHash(Failure:D:) { $!handled ?? SetHash.new(self) !! self!throw }
    method Bag(Failure:D:)     { $!handled ?? Bag.new(self)     !! self!throw }
    method BagHash(Failure:D:) { $!handled ?? BagHash.new(self) !! self!throw }
    method Mix(Failure:D:)     { $!handled ?? Mix.new(self)     !! self!throw }
    method MixHash(Failure:D:) { $!handled ?? MixHash.new(self) !! self!throw }

    multi method Str(Failure:D:)  { $!handled ?? $.mess !! self!throw(); }
    multi method gist(Failure:D:) { $!handled ?? $.mess !! self!throw(); }
    multi method gist(Failure:U:) { '(' ~ self.^name ~ ')' }
    multi method perl(Failure:D:) {
        $!handled ?? '&CORE::infix:<orelse>(' ~ self.Mu::perl ~ ', *.self)'
                  !! self.Mu::perl
    }
    multi method perl(Failure:U:) { self.^name }
    method mess (Failure:D:) {
        my $message = (try self.exception.message) // self.exception.^name ~ ' with no message';
        "(HANDLED) " x $!handled ~ "$message\n" ~ self.backtrace;
    }

    method sink(Failure:D:) {
        self!throw() unless $!handled
    }
    method self(Failure:D:) {
        self!throw() unless $!handled;
        self
    }
    method CALL-ME(Failure:D: |) {
        self!throw()
    }
    method FALLBACK(Failure:D: *@) {
        self!throw()
    }
    method STORE(Failure:D: *@) {
        self!throw()
    }
}

proto sub fail(|) {*};
multi sub fail(--> Nil) {
    my $stash := CALLER::;
    my $payload = $stash<$!>.DEFINITE ?? $stash<$!> !! "Failed";

    my $fail := Failure.new( $payload ~~ Exception
      ?? $payload !! X::AdHoc.new(:$payload));

    nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail);
    CATCH { $fail.exception.throw }
}
multi sub fail(Exception:U $e --> Nil) {
    my $fail := Failure.new(
        X::AdHoc.new(:payload("Failed with undefined " ~ $e.^name))
    );<commit_msg>Failure now first checks for existance of $! symbol<commit_after>my class Failure is Nil {
    has $.exception;
    has $.backtrace;
#?if !jvm
    has int $!handled;
#?endif
#?if jvm
    has Int $!handled;   # alas, native int breaks on the JVM
#?endif

    method !SET-SELF($!exception) {
        $!backtrace = $!exception.backtrace || Backtrace.new(3);
        $!exception.reset-backtrace;
        self
    }

    multi method new(Failure:D:) { self!throw }
    multi method new(Failure:U:) {
        my $stash := CALLER::LEXICAL::;
        my $payload = ($stash<$!>:exists && $stash<$!>.DEFINITE) ?? $stash<$!> !! "Failed";
        nqp::create(self)!SET-SELF(
          $payload ~~ Exception ?? $payload !! X::AdHoc.new(:$payload)
        )
    }
    multi method new(Failure:U: Exception:D \exception) {
        nqp::create(self)!SET-SELF(exception)
    }
    multi method new(Failure:U: $payload) {
        nqp::create(self)!SET-SELF(X::AdHoc.new(:$payload))
    }
    multi method new(Failure:U: |cap (*@msg)) {
        nqp::create(self)!SET-SELF(X::AdHoc.from-slurpy(|cap))
    }

    submethod DESTROY () {
        note "WARNING: unhandled Failure detected in DESTROY. If you meant "
            ~ "to ignore it, you can mark it as handled by calling .Bool, "
            ~ ".so, .not, or .defined methods. The Failure was:\n" ~ self.mess
        unless $!handled;
    }

    # allow Failures to throw when they replace an Iterable
    multi method iterator(Failure:D:) { self!throw }
    multi method list(Failure:D:)     { self!throw }

    # Marks the Failure has handled (since we're now fatalizing it) and throws.
    method !throw(Failure:D:) {
        $!handled = 1;
        $!exception.throw($!backtrace);
    }

    # Turns out multidimensional lookups are one way to leak unhandled failures, so
    # we'll just propagate the initial failure much as we propagate Nil on methods.
    method AT-POS(|) { self }
    method AT-KEY(|) { self }

    multi method defined(Failure:D: --> False) { $!handled = 1 }

    multi method Bool(Failure:D: --> False) { $!handled = 1 }
    method handled() is rw {
        Proxy.new(
          FETCH => {
#?if !jvm
              nqp::hllbool($!handled)
#?endif
#?if jvm
              $!handled.Bool
#?endif
          },
          STORE => -> $, $value { $!handled = $value.Bool.Numeric }
       )
    }

    method Capture() {
        self.DEFINITE.not || $!handled
            ?? X::Cannot::Capture.new(what => self).throw
            !! self!throw
    }
    method Int(Failure:D:)        { $!handled ?? Int !! self!throw(); }
    method Num(Failure:D:)        { $!handled ?? NaN !! self!throw(); }
    method Numeric(Failure:D:)    { $!handled ?? NaN !! self!throw(); }

    method Set(Failure:D:)     { $!handled ?? Set.new(self)     !! self!throw }
    method SetHash(Failure:D:) { $!handled ?? SetHash.new(self) !! self!throw }
    method Bag(Failure:D:)     { $!handled ?? Bag.new(self)     !! self!throw }
    method BagHash(Failure:D:) { $!handled ?? BagHash.new(self) !! self!throw }
    method Mix(Failure:D:)     { $!handled ?? Mix.new(self)     !! self!throw }
    method MixHash(Failure:D:) { $!handled ?? MixHash.new(self) !! self!throw }

    multi method Str(Failure:D:)  { $!handled ?? $.mess !! self!throw(); }
    multi method gist(Failure:D:) { $!handled ?? $.mess !! self!throw(); }
    multi method gist(Failure:U:) { '(' ~ self.^name ~ ')' }
    multi method perl(Failure:D:) {
        $!handled ?? '&CORE::infix:<orelse>(' ~ self.Mu::perl ~ ', *.self)'
                  !! self.Mu::perl
    }
    multi method perl(Failure:U:) { self.^name }
    method mess (Failure:D:) {
        my $message = (try self.exception.message) // self.exception.^name ~ ' with no message';
        "(HANDLED) " x $!handled ~ "$message\n" ~ self.backtrace;
    }

    method sink(Failure:D:) {
        self!throw() unless $!handled
    }
    method self(Failure:D:) {
        self!throw() unless $!handled;
        self
    }
    method CALL-ME(Failure:D: |) {
        self!throw()
    }
    method FALLBACK(Failure:D: *@) {
        self!throw()
    }
    method STORE(Failure:D: *@) {
        self!throw()
    }
}

proto sub fail(|) {*};
multi sub fail(--> Nil) {
    my $stash := CALLER::LEXICAL::;
    my $payload = ($stash<$!>:exists && $stash<$!>.DEFINITE) ?? $stash<$!> !! "Failed";

    my $fail := Failure.new( $payload ~~ Exception
      ?? $payload !! X::AdHoc.new(:$payload));

    nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail);
    CATCH { $fail.exception.throw }
}
multi sub fail(Exception:U $e --> Nil) {
    my $fail := Failure.new(
        X::AdHoc.new(:payload("Failed with undefined " ~ $e.^name))
    );
{'fraction_non_alphanumeric': 0.17431588019823313, 'fraction_numerical': 0.0008618832148243913, 'mean_word_length': 2.5745090489025797, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2090044', 'n_tokens_mistral': 3267, 'n_tokens_neox': 3104, 'n_words': 721}