/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /*! * \file tvm/ir/error.h * \brief Utilities for error tracking and reporting. */ #ifndef TVM_IR_ERROR_H_ #define TVM_IR_ERROR_H_ #include <tvm/ir/span.h> #include <tvm/ir/module.h> #include <string> #include <vector> #include <sstream> #include <unordered_map> namespace tvm { /*! * \brief A wrapper around std::stringstream to build error. * * Can be consumed by Error to construct an error. * * \code * * void ReportError(const Error& err); * * void Test(int number) { * // Use error reporter to construct an error. * ReportError(ErrorBuilder() << "This is an error number=" << number); * } * * \endcode */ struct ErrorBuilder { public: template<typename T> ErrorBuilder& operator<<(const T& val) { // NOLINT(*) stream_ << val; return *this; } private: std::stringstream stream_; friend class Error; }; /*! * \brief Custom Error class to be thrown during compilation. */ class Error : public dmlc::Error { public: /*! \brief Location of the error */ Span span; /*! * \brief construct error from message. * \param msg The message */ explicit Error(const std::string& msg) : dmlc::Error(msg), span(nullptr) {} /*! * \brief construct error from error builder. * \param err The error builder */ Error(const ErrorBuilder& err) : dmlc::Error(err.stream_.str()), span(nullptr) {} // NOLINT(*) /*! * \brief copy constructor. * \param other The other ereor. */ Error(const Error& other) : dmlc::Error(other.what()), span(other.span) {} // NOLINT(*) /*! * \brief default constructor. */ Error() : dmlc::Error(""), span(nullptr) {} }; /*! * \brief An abstraction around how errors are stored and reported. * Designed to be opaque to users, so we can support a robust and simpler * error reporting mode, as well as a more complex mode. * * The first mode is the most accurate: we report a Relay error at a specific * Span, and then render the error message directly against a textual representation * of the program, highlighting the exact lines in which it occurs. This mode is not * implemented in this PR and will not work. * * The second mode is a general-purpose mode, which attempts to annotate the program's * textual format with errors. * * The final mode represents the old mode, if we report an error that has no span or * expression, we will default to throwing an exception with a textual representation * of the error and no indication of where it occurred in the original program. * * The latter mode is not ideal, and the goal of the new error reporting machinery is * to avoid ever reporting errors in this style. */ class ErrorReporter { public: /*! \brief default constructor. */ ErrorReporter() : errors_(), node_to_error_() {} /*! * \brief Report a tvm::Error. * * This API is useful for reporting spanned errors. * * \param err The error to report. */ void Report(const Error& err) { if (!err.span.defined()) { throw err; } this->errors_.push_back(err); } /*! * \brief Report an error against a program, using the full program * error reporting strategy. * * This error reporting method requires the global function in which * to report an error, the expression to report the error on, * and the error object. * * \param global The global function in which the expression is contained. * \param node The expression or type to report the error at. * \param err The error message to report. */ void ReportAt(const GlobalVar& global, const ObjectRef& node, std::stringstream& err) { std::string err_msg = err.str(); this->ReportAt(global, node, Error(err_msg)); } /*! * \brief Report an error against a program, using the full program * error reporting strategy. * * This error reporting method requires the global function in which * to report an error, the expression to report the error on, * and the error object. * * \param global The global function in which the expression is contained. * \param node The expression or type to report the error at. * \param err The error to report. */ void ReportAt(const GlobalVar& global, const ObjectRef& node, const Error& err); /*! * \brief Render all reported errors and exit the program. * * This function should be used after executing a pass to render reported errors. * * It will build an error message from the set of errors, depending on the error * reporting strategy. * * \param module The module to report errors on. * \param use_color Controls whether to colorize the output. */ void RenderErrors(const IRModule& module, bool use_color = true); inline bool AnyErrors() { return errors_.size() != 0; } private: std::vector<Error> errors_; std::unordered_map<ObjectRef, std::vector<size_t>, ObjectHash, ObjectEqual> node_to_error_; std::unordered_map<ObjectRef, GlobalVar, ObjectHash, ObjectEqual> node_to_gv_; }; } // namespace tvm #endif // TVM_IR_ERROR_H_