blob: ac7b96a3bd597c5ff1a4db0285f037bfdfd6ff60 [file] [log] [blame]
/*
* 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/module.h>
#include <tvm/ir/span.h>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
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>, ObjectPtrHash, ObjectPtrEqual> node_to_error_;
std::unordered_map<ObjectRef, GlobalVar, ObjectPtrHash, ObjectPtrEqual> node_to_gv_;
};
} // namespace tvm
#endif // TVM_IR_ERROR_H_