Skip to content
Snippets Groups Projects
Unverified Commit 465480d3 authored by Ariya Hidayat's avatar Ariya Hidayat Committed by GitHub
Browse files

Reject less/greater than operators on booleans (#18206)

parent 8c085863
No related branches found
No related tags found
No related merge requests found
......@@ -3,6 +3,8 @@ import { ngettext, msgid, t } from "ttag";
import { ExpressionVisitor } from "./visitor";
import { CLAUSE_TOKENS } from "./lexer";
import { MBQL_CLAUSES, getMBQLName } from "./config";
export function typeCheck(cst, rootType) {
class TypeChecker extends ExpressionVisitor {
constructor() {
......@@ -30,7 +32,7 @@ export function typeCheck(cst, rootType) {
return result;
}
relationalExpression(ctx) {
this.typeStack.unshift("expression");
this.typeStack.unshift("number");
const result = super.relationalExpression(ctx);
this.typeStack.shift();
......@@ -79,6 +81,18 @@ export function typeCheck(cst, rootType) {
);
this.errors.push({ message });
} else {
// check for return value sub-type mismatch
const type = this.typeStack[0];
if (type === "number") {
const op = getMBQLName(name);
const returnType = MBQL_CLAUSES[op].type;
if (returnType !== "number" && returnType !== "string") {
const message = t`Expecting ${type} but found function ${name} returning ${returnType}`;
this.errors.push({ message });
}
}
// check for argument type matching
return args.map((arg, index) => {
const argType = clause.args[index];
const genericType =
......
......@@ -176,6 +176,19 @@ describe("type-checker", () => {
expect(() => validate("CONTAINS([Type],'X','Y')")).toThrow();
expect(() => validate("CONTAINS([Type],'P','Q','R')")).toThrow();
});
it("should allow a comparison (lexicographically) on strings", () => {
expect(() => validate("'A' <= 'B'")).not.toThrow();
});
it("should allow a comparison (lexicographically) on functions returning string", () => {
expect(() => validate("Lower([State]) > 'AB'")).not.toThrow();
});
it("should reject a less/greater comparison on functions returning boolean", () => {
expect(() => validate("IsEmpty([Tax]) < 5")).toThrow();
expect(() => validate("IsEmpty([Tax]) >= 0")).toThrow();
});
});
describe("for an aggregation", () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment