From 33c91a04f758c89f0402994a6df894e6c2032def Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Sun, 19 Nov 2017 20:17:07 +0100 Subject: [PATCH] vala: Allow unscoped enum values where possible If the scope for an enumeration value can be determined from current context it is possible to omit the enum's scope. Based on patch by Timo Kluck https://bugzilla.gnome.org/show_bug.cgi?id=666035 --- tests/Makefile.am | 1 + tests/enums/bug666035.vala | 58 ++++++++++++++++++++++++++++++++++ vala/valabinaryexpression.vala | 18 +++++++++++ vala/valamemberaccess.vala | 11 +++++++ vala/valaswitchlabel.vala | 16 +++++++++- 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 tests/enums/bug666035.vala diff --git a/tests/Makefile.am b/tests/Makefile.am index 86bc2c406..c64a2cd01 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -120,6 +120,7 @@ TESTS = \ enums/enum_only.vala \ enums/enums.vala \ enums/flags.vala \ + enums/bug666035.vala \ enums/bug673879.vala \ enums/bug763831.vala \ enums/bug780050.vala \ diff --git a/tests/enums/bug666035.vala b/tests/enums/bug666035.vala new file mode 100644 index 000000000..16c65d1ca --- /dev/null +++ b/tests/enums/bug666035.vala @@ -0,0 +1,58 @@ +enum FooEnum { + FOO, + BAR, + MAM; +} + +[Flags] +enum FooFlag { + FOO = 1 << 0, + BAR = 1 << 1, + MAM = 1 << 2; +} + +struct FooStruct { + public FooEnum f; +} + +FooEnum takes_enum (FooEnum foo) { + return foo; +} + +FooEnum gives_enum () { + return MAM; +} + +FooFlag takes_flag (FooFlag foo) { + return foo; +} + +FooFlag gives_flag () { + return MAM | BAR; +} + +void main () { + if (takes_enum (BAR) == BAR) + return; + + assert (takes_enum (BAR) == BAR); + //TODO assert (MAM == gives_enum ()); + + assert (takes_flag (BAR | MAM) == (BAR | MAM)); + //TODO assert (FOO == takes_flag (BAR & MAM | FOO)); + assert (gives_flag () == (BAR | MAM)); + + FooEnum[] foo_array = { FOO, BAR, FOO }; + foo_array[1] = MAM; + assert (foo_array[1] == MAM); + + FooStruct foo_struct = { BAR }; + assert (foo_struct.f == BAR); + + FooEnum foo_enum = BAR; + switch (foo_enum) { + default: + case FOO: assert (false); break; + case BAR: break; + } +} diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala index 19287da85..afdc75640 100644 --- a/vala/valabinaryexpression.vala +++ b/vala/valabinaryexpression.vala @@ -279,6 +279,24 @@ public class Vala.BinaryExpression : Expression { return true; } + // enum-type inference + if (target_type != null && target_type.data_type is Enum + && (operator == BinaryOperator.BITWISE_AND || operator == BinaryOperator.BITWISE_OR)) { + left.target_type = target_type.copy (); + right.target_type = target_type.copy (); + } + left.check (context); + if (left.value_type != null && left.value_type.data_type is Enum + && (operator == BinaryOperator.EQUALITY || operator == BinaryOperator.INEQUALITY)) { + right.target_type = left.value_type.copy (); + } + right.check (context); + if (right.value_type != null && right.value_type.data_type is Enum + && (operator == BinaryOperator.EQUALITY || operator == BinaryOperator.INEQUALITY)) { + left.target_type = right.value_type.copy (); + //TODO bug 666035 -- re-check left how? + } + if (!left.check (context) || !right.check (context)) { /* if there were any errors in inner expressions, skip type check */ error = true; diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index c00f5fca5..30143532e 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -452,6 +452,17 @@ public class Vala.MemberAccess : Expression { } } + // enum-type inference + if (symbol_reference == null && target_type != null && target_type.data_type is Enum) { + var enum_type = (Enum) target_type.data_type; + foreach (var val in enum_type.get_values ()) { + if (member_name == val.name) { + symbol_reference = val; + break; + } + } + } + if (symbol_reference == null) { error = true; diff --git a/vala/valaswitchlabel.vala b/vala/valaswitchlabel.vala index 9468b0ed3..99fbb4a69 100644 --- a/vala/valaswitchlabel.vala +++ b/vala/valaswitchlabel.vala @@ -69,9 +69,23 @@ public class Vala.SwitchLabel : CodeNode { public override bool check (CodeContext context) { if (expression != null) { + var switch_statement = (SwitchStatement) section.parent_node; + + // enum-type inference + var condition_target_type = switch_statement.expression.target_type; + if (expression.symbol_reference == null && condition_target_type != null && condition_target_type.data_type is Enum) { + var enum_type = (Enum) condition_target_type.data_type; + foreach (var val in enum_type.get_values ()) { + if (expression.to_string () == val.name) { + expression.target_type = condition_target_type.copy (); + expression.symbol_reference = val; + break; + } + } + } + expression.check (context); - var switch_statement = (SwitchStatement) section.parent_node; if (!expression.is_constant ()) { error = true; Report.error (expression.source_reference, "Expression must be constant"); -- 2.47.2