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