1//===- LogicalResult.h - Utilities for handling success/failure -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef MLIR_SUPPORT_LOGICALRESULT_H
10#define MLIR_SUPPORT_LOGICALRESULT_H
11
12#include "mlir/Support/LLVM.h"
13#include <optional>
14
15namespace mlir {
16
17/// This class represents an efficient way to signal success or failure. It
18/// should be preferred over the use of `bool` when appropriate, as it avoids
19/// all of the ambiguity that arises in interpreting a boolean result. This
20/// class is marked as NODISCARD to ensure that the result is processed. Users
21/// may explicitly discard a result by using `(void)`, e.g.
22/// `(void)functionThatReturnsALogicalResult();`. Given the intended nature of
23/// this class, it generally shouldn't be used as the result of functions that
24/// very frequently have the result ignored. This class is intended to be used
25/// in conjunction with the utility functions below.
26struct [[nodiscard]] LogicalResult {
27public:
28 /// If isSuccess is true a `success` result is generated, otherwise a
29 /// 'failure' result is generated.
30 static LogicalResult success(bool isSuccess = true) {
31 return LogicalResult(isSuccess);
32 }
33
34 /// If isFailure is true a `failure` result is generated, otherwise a
35 /// 'success' result is generated.
36 static LogicalResult failure(bool isFailure = true) {
37 return LogicalResult(!isFailure);
38 }
39
40 /// Returns true if the provided LogicalResult corresponds to a success value.
41 bool succeeded() const { return isSuccess; }
42
43 /// Returns true if the provided LogicalResult corresponds to a failure value.
44 bool failed() const { return !isSuccess; }
45
46private:
47 LogicalResult(bool isSuccess) : isSuccess(isSuccess) {}
48
49 /// Boolean indicating if this is a success result, if false this is a
50 /// failure result.
51 bool isSuccess;
52};
53
54/// Utility function to generate a LogicalResult. If isSuccess is true a
55/// `success` result is generated, otherwise a 'failure' result is generated.
56inline LogicalResult success(bool isSuccess = true) {
57 return LogicalResult::success(isSuccess);
58}
59
60/// Utility function to generate a LogicalResult. If isFailure is true a
61/// `failure` result is generated, otherwise a 'success' result is generated.
62inline LogicalResult failure(bool isFailure = true) {
63 return LogicalResult::failure(isFailure);
64}
65
66/// Utility function that returns true if the provided LogicalResult corresponds
67/// to a success value.
68inline bool succeeded(LogicalResult result) { return result.succeeded(); }
69
70/// Utility function that returns true if the provided LogicalResult corresponds
71/// to a failure value.
72inline bool failed(LogicalResult result) { return result.failed(); }
73
74/// This class provides support for representing a failure result, or a valid
75/// value of type `T`. This allows for integrating with LogicalResult, while
76/// also providing a value on the success path.
77template <typename T>
78class [[nodiscard]] FailureOr : public std::optional<T> {
79public:
80 /// Allow constructing from a LogicalResult. The result *must* be a failure.
81 /// Success results should use a proper instance of type `T`.
82 FailureOr(LogicalResult result) {
83 assert(failed(result) &&
84 "success should be constructed with an instance of 'T'");
85 }
86 FailureOr() : FailureOr(failure()) {}
87 FailureOr(T &&y) : std::optional<T>(std::forward<T>(y)) {}
88 FailureOr(const T &y) : std::optional<T>(y) {}
89 template <typename U,
90 std::enable_if_t<std::is_constructible<T, U>::value> * = nullptr>
91 FailureOr(const FailureOr<U> &other)
92 : std::optional<T>(failed(other) ? std::optional<T>()
93 : std::optional<T>(*other)) {}
94
95 operator LogicalResult() const { return success(this->has_value()); }
96
97private:
98 /// Hide the bool conversion as it easily creates confusion.
99 using std::optional<T>::operator bool;
100 using std::optional<T>::has_value;
101};
102
103/// Wrap a value on the success path in a FailureOr of the same value type.
104template <typename T,
105 typename = std::enable_if_t<!std::is_convertible_v<T, bool>>>
106inline auto success(T &&t) {
107 return FailureOr<std::decay_t<T>>(std::forward<T>(t));
108}
109
110/// This class represents success/failure for parsing-like operations that find
111/// it important to chain together failable operations with `||`. This is an
112/// extended version of `LogicalResult` that allows for explicit conversion to
113/// bool.
114///
115/// This class should not be used for general error handling cases - we prefer
116/// to keep the logic explicit with the `succeeded`/`failed` predicates.
117/// However, traditional monadic-style parsing logic can sometimes get
118/// swallowed up in boilerplate without this, so we provide this for narrow
119/// cases where it is important.
120///
121class [[nodiscard]] ParseResult : public LogicalResult {
122public:
123 ParseResult(LogicalResult result = success()) : LogicalResult(result) {}
124
125 /// Failure is true in a boolean context.
126 explicit operator bool() const { return failed(); }
127};
128
129} // namespace mlir
130
131#endif // MLIR_SUPPORT_LOGICALRESULT_H
132

source code of mlir/include/mlir/Support/LogicalResult.h