1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19#ifndef TVM_RELAY_ERROR_H_
20#define TVM_RELAY_ERROR_H_
21
22#include <tvm/ir/module.h>
23
24#include <sstream>
25#include <string>
26#include <unordered_map>
27#include <vector>
28
29namespace tvm {
30namespace relay {
31/*!
32 * \brief A wrapper around std::stringstream to build error.
33 *include/tvm/ir/type.h
34 * Can be consumed by CompileError to construct an error.
35 *
36 * \code
37 *
38 * void ReportError(const CompileError& err);
39 *
40 * void Test(int number) {
41 * // Use error reporter to construct an error.
42 * ReportError(ErrorBuilder() << "This is an error number=" << number);
43 * }
44 *
45 * \endcode
46 */
47struct ErrorBuilder {
48 public:
49 template <typename T>
50 ErrorBuilder& operator<<(const T& val) { // NOLINT(*)
51 stream_ << val;
52 return *this;
53 }
54
55 private:
56 std::stringstream stream_;
57 friend class CompileError;
58};
59
60/*!
61 * \brief Custom Error class to be thrown during compilation.
62 */
63class CompileError : public Error {
64 public:
65 /*! \brief Location of the error */
66 Span span;
67 /*!
68 * \brief construct error from message.
69 * \param msg The message
70 */
71 explicit CompileError(const std::string& msg) : Error(msg), span(nullptr) {}
72 /*!
73 * \brief construct error from error builder.
74 * \param err The error builder
75 */
76 CompileError(const ErrorBuilder& err) : Error(err.stream_.str()), span(nullptr) {} // NOLINT(*)
77 /*!
78 * \brief copy constructor.
79 * \param other The other ereor.
80 */
81 CompileError(const CompileError& other) : Error(other.what()), span(other.span) {} // NOLINT(*)
82 /*!
83 * \brief default constructor. */
84 CompileError() : Error(""), span(nullptr) {}
85};
86
87/*!
88 * \brief An abstraction around how errors are stored and reported.
89 * Designed to be opaque to users, so we can support a robust and simpler
90 * error reporting mode, as well as a more complex mode.
91 *
92 * The first mode is the most accurate: we report a Relay error at a specific
93 * Span, and then render the error message directly against a textual representation
94 * of the program, highlighting the exact lines in which it occurs. This mode is not
95 * implemented in this PR and will not work.
96 *
97 * The second mode is a general-purpose mode, which attempts to annotate the program's
98 * textual format with errors.
99 *
100 * The final mode represents the old mode, if we report an error that has no span or
101 * expression, we will default to throwing an exception with a textual representation
102 * of the error and no indication of where it occurred in the original program.
103 *
104 * The latter mode is not ideal, and the goal of the new error reporting machinery is
105 * to avoid ever reporting errors in this style.
106 */
107class ErrorReporter {
108 public:
109 /*! \brief default constructor. */
110 ErrorReporter() : errors_(), node_to_error_() {}
111
112 /*!
113 * \brief Report a CompileError.
114 *
115 * This API is useful for reporting spanned errors.
116 *
117 * \param err The error to report.
118 */
119 void Report(const CompileError& err) {
120 if (!err.span.defined()) {
121 throw err;
122 }
123
124 this->errors_.push_back(err);
125 }
126
127 /*!
128 * \brief Report an error against a program, using the full program
129 * error reporting strategy.
130 *
131 * This error reporting method requires the global function in which
132 * to report an error, the expression to report the error on,
133 * and the error object.
134 *
135 * \param global The global function in which the expression is contained.
136 * \param node The expression or type to report the error at.
137 * \param err The error message to report.
138 */
139 void ReportAt(const GlobalVar& global, const ObjectRef& node, std::stringstream& err) {
140 std::string err_msg = err.str();
141 this->ReportAt(global, node, CompileError(err_msg));
142 }
143
144 /*!
145 * \brief Report an error against a program, using the full program
146 * error reporting strategy.
147 *
148 * This error reporting method requires the global function in which
149 * to report an error, the expression to report the error on,
150 * and the error object.
151 *
152 * \param global The global function in which the expression is contained.
153 * \param node The expression or type to report the error at.
154 * \param err The error to report.
155 */
156 void ReportAt(const GlobalVar& global, const ObjectRef& node, const CompileError& err);
157
158 /*!
159 * \brief Render all reported errors and exit the program.
160 *
161 * This function should be used after executing a pass to render reported errors.
162 *
163 * It will build an error message from the set of errors, depending on the error
164 * reporting strategy.
165 *
166 * \param module The module to report errors on.
167 * \param use_color Controls whether to colorize the output.
168 */
169 void RenderErrors(const IRModule& module, bool use_color = true);
170
171 inline bool AnyErrors() { return errors_.size() != 0; }
172
173 private:
174 std::vector<CompileError> errors_;
175 std::unordered_map<ObjectRef, std::vector<size_t>, ObjectPtrHash, ObjectPtrEqual> node_to_error_;
176 std::unordered_map<ObjectRef, GlobalVar, ObjectPtrHash, ObjectPtrEqual> node_to_gv_;
177};
178
179} // namespace relay
180} // namespace tvm
181#endif // TVM_RELAY_ERROR_H_
182