Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VarWellFormed #5

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/tvm/relay/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ struct InternalError : Error {
explicit InternalError(const std::string &msg) : Error(msg) {}
};

struct SpannedError {
std::string msg;
Span sp;
SpannedError(const std::string &msg, Span sp) : msg(msg), sp(sp) {}
};

// FIX, we should change spanned errors to have a method which allow them to
// report on the Environment, inverting control to error definition.
struct FatalTypeError : dmlc::Error {
Expand Down
12 changes: 12 additions & 0 deletions include/tvm/relay/expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <tvm/node.h>
#include <tvm/attrs.h>
#include <string>
#include <functional>
#include "./base.h"
#include "./type.h"

Expand Down Expand Up @@ -370,4 +371,15 @@ RELAY_DEFINE_NODE_REF(If, IfNode, Expr);

} // namespace relay
} // namespace tvm

namespace std {

template<>
struct hash<::tvm::relay::Var> {
std::size_t operator()(const ::tvm::relay::Var & lv) const {
return lv.hash();
}
};

}
#endif // TVM_RELAY_EXPR_H_
15 changes: 15 additions & 0 deletions include/tvm/relay/pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ Expr InferType(const Environment& env, const GlobalVar & v, const Function & e);
*/
bool KindCheck(const Environment& env, const Type& t);

/*! brief Check that no LocalVar got shadowed.
*
* Roughly speaking, a LocalVar is considered to be shadowed, if it was introduce while it was already in scoped.
*
* For example, the expression `let x = 1 in let x = 2 in 3` shadow x.
*
* However, `let f = (\x -> x) in let g = (\x -> x + 1) in f(g(2))` does not shadow x, f, g.
* x is not shadowed because it is introduce at other scoped - the x used by f is invisible to the x used by g.
*
* \param e the expression to check.
*
* \return true iff e has no shadowing.
*/
bool LocalVarWellFormed(const Expr & e);

} // namespace relay
} // namespace tvm
#endif // TVM_RELAY_PASS_H_
56 changes: 56 additions & 0 deletions src/relay/pass/var_well_formed.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*!
* Copyright (c) 2018 by Contributors
* \file var_well_formed.cc
* \brief Function for substituting a concrete type in place of a type ID
*/
#include <tvm/relay/pass.h>
#include <tvm/relay/expr_visitor.h>
#include <unordered_set>

namespace tvm {
namespace relay {

struct ShadowDetected { };

struct DetectShadow : ExprVisitor {
struct Insert {
DetectShadow * ds;
Var lv;
Insert(DetectShadow * ds, const Var & lv) : ds(ds), lv(lv) {
if (ds->s.count(lv) != 0) {
throw ShadowDetected();
}
ds->s.insert(lv);
}
Insert(const Insert &) = delete;
Insert(Insert &&) = default;
~Insert() {
ds->s.erase(lv);
}
};
std::unordered_set<Var> s;
void VisitExpr_(const LetNode & l) {
Insert ins(this, l.var);
(*this)(l.value); // we do letrec only for FunctionNode, but shadowing let in let binding is dangerous, and we should forbidden it.
(*this)(l.body);
}
void VisitExpr_(const FunctionNode & f) {
std::vector<Insert> ins;
for (const Param & p : f.params) {
ins.push_back(Insert(this, p->var));
}
(*this)(f.body);
}
};

bool VarWellFormed(const Expr & e) {
try {
DetectShadow()(e);
return true;
} catch (const ShadowDetected &) {
return false;
}
}

} // namespace relay
} // namespace tvm