summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwszqkzqk <wszqkzqk@qq.com>2022-12-13 21:56:53 +0800
committerRico Tzschichholz <ricotz@ubuntu.com>2022-12-22 17:13:52 +0100
commitc5679d09cdc8b49c9b886fc6617db901350c301d (patch)
treea75445dfdeaef656e8c03140f793028c3e746369
parenta67d19f51082944e3751760d6c0ae09efc35b860 (diff)
downloadvala-c5679d09cdc8b49c9b886fc6617db901350c301d.tar.gz
parser: Properly handle chained equality expressions
Fixes https://gitlab.gnome.org/GNOME/vala/issues/1385
-rw-r--r--codegen/valaccodebasemodule.vala13
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/parser/chained-equality-type-invalid.test8
-rw-r--r--tests/parser/chained-equality.c-expected212
-rw-r--r--tests/parser/chained-equality.vala70
-rw-r--r--vala/valabinaryexpression.vala44
-rw-r--r--vala/valaparser.vala27
7 files changed, 342 insertions, 34 deletions
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 2969679c9..c8301c821 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -5842,8 +5842,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
}
}
- bool is_string_comparison = !(expr.left.value_type is NullType) && expr.left.value_type.compatible (string_type)
- && !(expr.right.value_type is NullType) && expr.right.value_type.compatible (string_type);
+ bool is_string_comparison = false;
+ if (!(expr.right.value_type is NullType) && expr.right.value_type.compatible (string_type)) {
+ if (!(expr.left.value_type is NullType) && expr.left.value_type.compatible (string_type)) {
+ is_string_comparison = true;
+ } else if (expr.is_chained) {
+ unowned BinaryExpression lbe = (BinaryExpression) expr.left;
+ if (!(lbe.right.value_type is NullType) && lbe.right.value_type.compatible (string_type)) {
+ is_string_comparison = true;
+ }
+ }
+ }
bool has_string_literal = (expr.left is StringLiteral || expr.right is StringLiteral);
if (is_string_comparison || (has_string_literal && expr.operator != BinaryOperator.PLUS)) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 94346acf3..407bffc5b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -931,6 +931,8 @@ TESTS = \
parser/attribute-missing-literal.test \
parser/attribute-wrong-number.test \
parser/block-delimiter-missing.test \
+ parser/chained-equality-type-invalid.test \
+ parser/chained-equality.vala \
parser/constant-owned.test \
parser/constant-local-owned.test \
parser/constructor-class-exists.test \
diff --git a/tests/parser/chained-equality-type-invalid.test b/tests/parser/chained-equality-type-invalid.test
new file mode 100644
index 000000000..e280245ed
--- /dev/null
+++ b/tests/parser/chained-equality-type-invalid.test
@@ -0,0 +1,8 @@
+Invalid Code
+
+void main () {
+ var foo = "world";
+ var bar = 0;
+ if (foo == "world" != 0) {
+ }
+}
diff --git a/tests/parser/chained-equality.c-expected b/tests/parser/chained-equality.c-expected
new file mode 100644
index 000000000..3e59b5d34
--- /dev/null
+++ b/tests/parser/chained-equality.c-expected
@@ -0,0 +1,212 @@
+/* parser_chained_equality.c generated by valac, the Vala compiler
+ * generated from parser_chained_equality.vala, do not modify */
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+
+static void _vala_main (void);
+
+static void
+_vala_main (void)
+{
+ {
+ gint foo = 0;
+ gint bar = 0;
+ gint _tmp0_;
+ foo = 123;
+ bar = 123;
+ _tmp0_ = bar;
+ _vala_assert ((foo == _tmp0_) && (_tmp0_ == 123), "foo == bar == 123");
+ }
+ {
+ gint foo = 0;
+ gint bar = 0;
+ gint _tmp1_;
+ foo = 111;
+ bar = 222;
+ _tmp1_ = bar;
+ _vala_assert ((foo != _tmp1_) && (_tmp1_ == 222), "foo != bar == 222");
+ }
+ {
+ gint foo = 0;
+ gint bar = 0;
+ gint _tmp2_;
+ foo = 111;
+ bar = 111;
+ _tmp2_ = bar;
+ _vala_assert ((foo == _tmp2_) && (_tmp2_ != 222), "foo == bar != 222");
+ }
+ {
+ gint foo = 0;
+ gint bar = 0;
+ gint _tmp3_;
+ gint _tmp4_;
+ foo = 111;
+ bar = 111;
+ _tmp3_ = foo;
+ _tmp4_ = bar;
+ _vala_assert (((0 < _tmp3_) && (_tmp3_ == _tmp4_)) && (_tmp4_ < 222), "0 < foo == bar < 222");
+ }
+ {
+ gint a = 0;
+ gint b = 0;
+ gint c = 0;
+ gint _tmp5_;
+ gint _tmp6_;
+ a = 111;
+ b = 111;
+ c = 111;
+ _tmp5_ = b;
+ _tmp6_ = c;
+ _vala_assert (((a == _tmp5_) && (_tmp5_ == _tmp6_)) && (_tmp6_ == 111), "a == b == c == 111");
+ }
+ {
+ gint a = 0;
+ gint b = 0;
+ gint c = 0;
+ gint _tmp7_;
+ gint _tmp8_;
+ a = 111;
+ b = 222;
+ c = 333;
+ _tmp7_ = b;
+ _tmp8_ = c;
+ _vala_assert (((a != _tmp7_) && (_tmp7_ != _tmp8_)) && (_tmp8_ != 123), "a != b != c != 123");
+ }
+ {
+ gchar* foo = NULL;
+ gchar* _tmp9_;
+ gchar* bar = NULL;
+ gchar* _tmp10_;
+ gchar* _tmp11_;
+ _tmp9_ = g_strdup ("world");
+ foo = _tmp9_;
+ _tmp10_ = g_strdup ("hello");
+ bar = _tmp10_;
+ _tmp11_ = bar;
+ _vala_assert ((g_strcmp0 (foo, _tmp11_) > 0) && (g_strcmp0 (_tmp11_, "hello") == 0), "foo > bar == \"hello\"");
+ _g_free0 (bar);
+ _g_free0 (foo);
+ }
+ {
+ gchar* a = NULL;
+ gchar* _tmp12_;
+ gchar* b = NULL;
+ gchar* _tmp13_;
+ gchar* c = NULL;
+ gchar* _tmp14_;
+ gchar* _tmp15_;
+ gchar* _tmp16_;
+ gchar* _tmp17_;
+ gchar* _tmp18_;
+ _tmp12_ = g_strdup ("hello");
+ a = _tmp12_;
+ _tmp13_ = g_strdup ("hello");
+ b = _tmp13_;
+ _tmp14_ = g_strdup ("hello");
+ c = _tmp14_;
+ _tmp15_ = a;
+ _tmp16_ = b;
+ _tmp17_ = c;
+ _tmp18_ = "hello";
+ _vala_assert (((((g_strcmp0 ("hello", _tmp15_) == 0) && (g_strcmp0 (_tmp15_, _tmp16_) <= 0)) && (g_strcmp0 (_tmp16_, _tmp17_) == 0)) && (g_strcmp0 (_tmp17_, _tmp18_) == 0)) && (g_strcmp0 (_tmp18_, "hello") <= 0), "\"hello\" == a <= b == c == \"hello\" <= \"hello\"");
+ _g_free0 (c);
+ _g_free0 (b);
+ _g_free0 (a);
+ }
+ {
+ gchar* foo = NULL;
+ gchar* _tmp19_;
+ gchar* bar = NULL;
+ gchar* _tmp20_;
+ gchar* _tmp21_;
+ _tmp19_ = g_strdup ("h");
+ foo = _tmp19_;
+ _tmp20_ = g_strdup ("h");
+ bar = _tmp20_;
+ _tmp21_ = bar;
+ _vala_assert ((g_strcmp0 (foo, _tmp21_) == 0) && (g_strcmp0 (_tmp21_, "hello") < 0), "foo == bar < \"hello\"");
+ _g_free0 (bar);
+ _g_free0 (foo);
+ }
+ {
+ gchar* foo = NULL;
+ gchar* _tmp22_;
+ gchar* bar = NULL;
+ gchar* _tmp23_;
+ gchar* _tmp24_;
+ _tmp22_ = g_strdup ("hello");
+ foo = _tmp22_;
+ _tmp23_ = g_strdup ("world");
+ bar = _tmp23_;
+ _tmp24_ = bar;
+ _vala_assert ((g_strcmp0 (foo, _tmp24_) != 0) && (g_strcmp0 (_tmp24_, "world") == 0), "foo != bar == \"world\"");
+ _g_free0 (bar);
+ _g_free0 (foo);
+ }
+ {
+ gchar* foo = NULL;
+ gchar* _tmp25_;
+ gchar* bar = NULL;
+ gchar* _tmp26_;
+ gchar* _tmp27_;
+ _tmp25_ = g_strdup ("world");
+ foo = _tmp25_;
+ _tmp26_ = g_strdup ("world");
+ bar = _tmp26_;
+ _tmp27_ = bar;
+ _vala_assert ((g_strcmp0 (foo, _tmp27_) == 0) && (g_strcmp0 (_tmp27_, "hello") != 0), "foo == bar != \"hello\"");
+ _g_free0 (bar);
+ _g_free0 (foo);
+ }
+ {
+ gchar* foo = NULL;
+ gchar* _tmp28_;
+ gchar* bar = NULL;
+ gchar* _tmp29_;
+ gchar* _tmp30_;
+ gint _tmp31_;
+ _tmp28_ = g_strdup ("world");
+ foo = _tmp28_;
+ _tmp29_ = g_strdup ("world");
+ bar = _tmp29_;
+ _tmp30_ = bar;
+ _tmp31_ = 0;
+ _vala_assert (((g_strcmp0 (foo, _tmp30_) == 0) && (g_strcmp0 (_tmp30_, "hello") != 0)) == ((0 == _tmp31_) && (_tmp31_ <= 1)), "(foo == bar != \"hello\") == (0 == 0 <= 1)");
+ _g_free0 (bar);
+ _g_free0 (foo);
+ }
+ {
+ gchar* foo = NULL;
+ gchar* _tmp32_;
+ gchar* bar = NULL;
+ gchar* _tmp33_;
+ gchar* _tmp34_;
+ gint _tmp35_;
+ _tmp32_ = g_strdup ("world");
+ foo = _tmp32_;
+ _tmp33_ = g_strdup ("world");
+ bar = _tmp33_;
+ _tmp34_ = bar;
+ _tmp35_ = 1;
+ _vala_assert (((g_strcmp0 (foo, _tmp34_) == 0) && (g_strcmp0 (_tmp34_, "hello") == 0)) == ((1 == _tmp35_) && (_tmp35_ <= 0)), "(foo == bar == \"hello\") == (1 == 1 <= 0)");
+ _g_free0 (bar);
+ _g_free0 (foo);
+ }
+}
+
+int
+main (int argc,
+ char ** argv)
+{
+ _vala_main ();
+ return 0;
+}
+
diff --git a/tests/parser/chained-equality.vala b/tests/parser/chained-equality.vala
new file mode 100644
index 000000000..ce734af64
--- /dev/null
+++ b/tests/parser/chained-equality.vala
@@ -0,0 +1,70 @@
+void main () {
+ {
+ var foo = 123;
+ var bar = 123;
+ assert (foo == bar == 123);
+ }
+ {
+ var foo = 111;
+ var bar = 222;
+ assert (foo != bar == 222);
+ }
+ {
+ var foo = 111;
+ var bar = 111;
+ assert (foo == bar != 222);
+ }
+ {
+ var foo = 111;
+ var bar = 111;
+ assert (0 < foo == bar < 222);
+ }
+ {
+ var a = 111;
+ var b = 111;
+ var c = 111;
+ assert (a == b == c == 111);
+ }
+ {
+ var a = 111;
+ var b = 222;
+ var c = 333;
+ assert (a != b != c != 123);
+ }
+ {
+ var foo = "world";
+ var bar = "hello";
+ assert (foo > bar == "hello");
+ }
+ {
+ var a = "hello";
+ var b = "hello";
+ var c = "hello";
+ assert ("hello" == a <= b == c == "hello" <= "hello");
+ }
+ {
+ var foo = "h";
+ var bar = "h";
+ assert (foo == bar < "hello");
+ }
+ {
+ var foo = "hello";
+ var bar = "world";
+ assert (foo != bar == "world");
+ }
+ {
+ var foo = "world";
+ var bar = "world";
+ assert (foo == bar != "hello");
+ }
+ {
+ var foo = "world";
+ var bar = "world";
+ assert ((foo == bar != "hello") == (0 == 0 <= 1)); // true == true
+ }
+ {
+ var foo = "world";
+ var bar = "world";
+ assert ((foo == bar == "hello") == (1 == 1 <= 0)); // false == false
+ }
+}
diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala
index 6545e1cff..d627e2942 100644
--- a/vala/valabinaryexpression.vala
+++ b/vala/valabinaryexpression.vala
@@ -467,7 +467,12 @@ public class Vala.BinaryExpression : Expression {
DataType resulting_type;
if (is_chained) {
- var lbe = (BinaryExpression) left;
+ unowned BinaryExpression lbe = (BinaryExpression) left;
+ if (lbe.right.value_type.compatible (context.analyzer.string_type)
+ && right.value_type.compatible (context.analyzer.string_type)) {
+ value_type = context.analyzer.bool_type;
+ break;
+ }
resulting_type = context.analyzer.get_arithmetic_result_type (lbe.right.target_type, right.target_type);
} else {
resulting_type = context.analyzer.get_arithmetic_result_type (left.target_type, right.target_type);
@@ -475,7 +480,14 @@ public class Vala.BinaryExpression : Expression {
if (resulting_type == null) {
error = true;
- Report.error (source_reference, "Relational operation not supported for types `%s' and `%s'", left.value_type.to_string (), right.value_type.to_string ());
+ unowned DataType left_type;
+ if (is_chained) {
+ unowned BinaryExpression lbe = (BinaryExpression) left;
+ left_type = lbe.right.value_type;
+ } else {
+ left_type = left.value_type;
+ }
+ Report.error (source_reference, "Relational operation not supported for types `%s' and `%s'", left_type.to_string (), right.value_type.to_string ());
return false;
}
@@ -515,17 +527,31 @@ public class Vala.BinaryExpression : Expression {
}
}
- if (!right.value_type.compatible (left.value_type)
- && !left.value_type.compatible (right.value_type)) {
- Report.error (source_reference, "Equality operation: `%s' and `%s' are incompatible", right.value_type.to_string (), left.value_type.to_string ());
- error = true;
- return false;
+ DataType resulting_type;
+ if (is_chained) {
+ unowned BinaryExpression lbe = (BinaryExpression) left;
+ resulting_type = context.analyzer.get_arithmetic_result_type (lbe.right.target_type, right.target_type);
+ if (!right.value_type.compatible (lbe.right.value_type)
+ && !lbe.right.value_type.compatible (right.value_type)) {
+ Report.error (source_reference, "Equality operation: `%s' and `%s' are incompatible", right.value_type.to_string (), lbe.right.value_type.to_string ());
+ error = true;
+ return false;
+ }
+ } else {
+ resulting_type = context.analyzer.get_arithmetic_result_type (left.target_type, right.target_type);
+ if (!right.value_type.compatible (left.value_type)
+ && !left.value_type.compatible (right.value_type)) {
+ Report.error (source_reference, "Equality operation: `%s' and `%s' are incompatible", right.value_type.to_string (), left.value_type.to_string ());
+ error = true;
+ return false;
+ }
}
- var resulting_type = context.analyzer.get_arithmetic_result_type (left.target_type, right.target_type);
if (resulting_type != null) {
// numeric operation
- left.target_type = resulting_type.copy ();
+ if (!is_chained) {
+ left.target_type = resulting_type.copy ();
+ }
right.target_type = resulting_type.copy ();
}
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index d932b8b2d..25769ec54 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -1452,6 +1452,8 @@ public class Vala.Parser : CodeVisitor {
case BinaryOperator.LESS_THAN:
case BinaryOperator.LESS_THAN_OR_EQUAL:
case BinaryOperator.GREATER_THAN_OR_EQUAL:
+ case BinaryOperator.EQUALITY:
+ case BinaryOperator.INEQUALITY:
next ();
var right = parse_type_check_expression ();
if (first) {
@@ -1485,32 +1487,11 @@ public class Vala.Parser : CodeVisitor {
return left;
}
- Expression parse_equality_expression () throws ParseError {
- var begin = get_location ();
- var left = parse_relational_expression ();
- bool found = true;
- while (found) {
- var operator = get_binary_operator (current ());
- switch (operator) {
- case BinaryOperator.EQUALITY:
- case BinaryOperator.INEQUALITY:
- next ();
- var right = parse_relational_expression ();
- left = new BinaryExpression (operator, left, right, get_src (begin));
- break;
- default:
- found = false;
- break;
- }
- }
- return left;
- }
-
Expression parse_and_expression () throws ParseError {
var begin = get_location ();
- var left = parse_equality_expression ();
+ var left = parse_relational_expression ();
while (accept (TokenType.BITWISE_AND)) {
- var right = parse_equality_expression ();
+ var right = parse_relational_expression ();
left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
}
return left;