During type check Any type should always match

Reviewers: florijan, mislav.bradac

Reviewed By: florijan

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D286
This commit is contained in:
Teon Banek 2017-04-18 11:40:07 +02:00
parent dbe5ffc4ea
commit c1d0090fe1
3 changed files with 35 additions and 5 deletions

View File

@ -17,7 +17,9 @@ auto SymbolGenerator::GetOrCreateSymbol(const std::string &name,
auto search = scope_.symbols.find(name);
if (search != scope_.symbols.end()) {
auto symbol = search->second;
if (type != Symbol::Type::Any && type != symbol.type_) {
// Unless we have `Any` type, check that types match.
if (type != Symbol::Type::Any && symbol.type_ != Symbol::Type::Any &&
type != symbol.type_) {
throw TypeMismatchError(name, Symbol::TypeToString(symbol.type_),
Symbol::TypeToString(type));
}
@ -39,6 +41,7 @@ void SymbolGenerator::PostVisit(Return &ret) {
// Named expressions establish bindings for expressions which come after
// return, but not for the expressions contained inside.
symbol_table_[*named_expr] = CreateSymbol(named_expr->name_);
// Improvement to type checking system would be to infer the type of the expression.
}
scope_.in_return = false;
}
@ -54,6 +57,7 @@ bool SymbolGenerator::PreVisit(With &with) {
// be visible inside named expressions themselves.
scope_.symbols.clear();
for (auto &named_expr : with.named_expressions_) {
// Improvement would be to infer the type of the expression.
symbol_table_[*named_expr] = CreateSymbol(named_expr->name_);
}
if (with.where_) with.where_->Accept(*this);
@ -108,7 +112,8 @@ void SymbolGenerator::Visit(Aggregation &aggr) {
"allowed");
}
// Create a virtual symbol for aggregation result.
symbol_table_[aggr] = symbol_table_.CreateSymbol("");
// Currently, we only have aggregation operators which return numbers.
symbol_table_[aggr] = symbol_table_.CreateSymbol("", Symbol::Type::Number);
scope_.in_aggregation = true;
}
@ -120,7 +125,7 @@ void SymbolGenerator::PostVisit(Aggregation &aggr) {
void SymbolGenerator::Visit(Pattern &pattern) {
scope_.in_pattern = true;
if (scope_.in_create && pattern.atoms_.size() == 1) {
if (scope_.in_create && pattern.atoms_.size() == 1U) {
debug_assert(dynamic_cast<NodeAtom *>(pattern.atoms_[0]),
"Expected a single NodeAtom in Pattern");
scope_.in_create_node = true;
@ -157,7 +162,7 @@ void SymbolGenerator::Visit(EdgeAtom &edge_atom) {
scope_.in_edge_atom = true;
if (scope_.in_create) {
scope_.in_create_edge = true;
if (edge_atom.edge_types_.size() != 1) {
if (edge_atom.edge_types_.size() != 1U) {
throw SemanticException(
"A single relationship type must be specified "
"when creating an edge.");

View File

@ -10,7 +10,7 @@ namespace query {
class Symbol {
public:
// This is similar to TypedValue::Type, but this has `Any` type.
enum class Type { Any, Vertex, Edge, Path };
enum class Type { Any, Vertex, Edge, Path, Number };
static std::string TypeToString(Type type) {
const char *enum_string[] = {"Any", "Vertex", "Edge", "Path"};

View File

@ -509,4 +509,29 @@ TEST(TestSymbolGenerator, CreateNodeEdge) {
EXPECT_NE(n, symbol_table.at(*edge->identifier_));
}
TEST(TestSymbolGenerator, MatchWithCreate) {
// Test MATCH (n) WITH n AS m CREATE (m) -[r :r]-> (m)
Dbms dbms;
auto dba = dbms.active();
auto r_type = dba->edge_type("r");
AstTreeStorage storage;
auto node_1 = NODE("n");
auto node_2 = NODE("m");
auto edge = EDGE("r", r_type, EdgeAtom::Direction::RIGHT);
auto node_3 = NODE("m");
auto query = QUERY(MATCH(PATTERN(node_1)), WITH(IDENT("n"), AS("m")),
CREATE(PATTERN(node_2, edge, node_3)));
SymbolTable symbol_table;
SymbolGenerator symbol_generator(symbol_table);
query->Accept(symbol_generator);
EXPECT_EQ(symbol_table.max_position(), 3);
auto n = symbol_table.at(*node_1->identifier_);
EXPECT_EQ(n.type_, Symbol::Type::Vertex);
auto m = symbol_table.at(*node_2->identifier_);
EXPECT_NE(n, m);
// Currently we don't infer expression types, so we lost true type of 'm'.
EXPECT_EQ(m.type_, Symbol::Type::Any);
EXPECT_EQ(m, symbol_table.at(*node_3->identifier_));
}
}