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 | |
29 | namespace tvm { |
30 | namespace 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 | */ |
47 | struct 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 | */ |
63 | class 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 | */ |
107 | class 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 | |