[vala/wip/issue/894] vala: Add support for type narrowing
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/issue/894] vala: Add support for type narrowing
- Date: Thu, 2 Apr 2020 12:39:33 +0000 (UTC)
commit 57391837b85c652d9c2da59ebf3374fe81180828
Author: Rico Tzschichholz <ricotz ubuntu com>
Date: Thu Apr 2 14:30:10 2020 +0200
vala: Add support for type narrowing
This causes type of given variable to be narrowed for the correspoding
child block of an if-statement.
Foo foo = ...;
if (foo is Bar) {
// foo represents a Bar instance inside this block
}
This makes conditional-expressions behaving similar.
... = (foo is Bar) ? "foo is instance of Bar here" : "...";
Fixes https://gitlab.gnome.org/GNOME/vala/issues/894
tests/Makefile.am | 1 +
tests/objects/type-narrowing.vala | 42 +++++++++++++++++++++++++++++++++++++++
vala/valablock.vala | 5 +++++
vala/valaifstatement.vala | 27 +++++++++++++++++++++++++
4 files changed, 75 insertions(+)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9f956d793..851051951 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -413,6 +413,7 @@ TESTS = \
objects/signals-delegate-parameter.vala \
objects/signals-lambda-delegate.vala \
objects/singleton.vala \
+ objects/type-narrowing.vala \
objects/test-025.vala \
objects/test-026.vala \
objects/test-029.vala \
diff --git a/tests/objects/type-narrowing.vala b/tests/objects/type-narrowing.vala
new file mode 100644
index 000000000..978c0dcf9
--- /dev/null
+++ b/tests/objects/type-narrowing.vala
@@ -0,0 +1,42 @@
+class Foo {
+ public void manam () {
+ if (this is Bar) {
+ assert (this.str == "bar");
+ }
+ assert (((this is Bar) ? this.str : "foo") == "bar");
+
+ if (!(this is Bar)) {
+ assert_not_reached ();
+ } else {
+ assert (this.str == "bar");
+ }
+ assert ((!(this is Bar) ? "foo" : this.str) == "bar");
+ }
+}
+
+class Bar : Foo {
+ public string str;
+ public Bar (string s) {
+ str = s;
+ }
+}
+
+void manam (Foo foo) {
+ if (foo is Bar) {
+ assert (foo.str == "bar");
+ }
+ assert (((foo is Bar) ? foo.str : "foo") == "bar");
+
+ if (!(foo is Bar)) {
+ assert_not_reached ();
+ } else {
+ assert (foo.str == "bar");
+ }
+ assert ((!(foo is Bar) ? "foo" : foo.str) == "bar");
+}
+
+void main() {
+ var bar = new Bar ("bar");
+ bar.manam ();
+ manam (bar);
+}
diff --git a/vala/valablock.vala b/vala/valablock.vala
index a702ea011..b0b1f64eb 100644
--- a/vala/valablock.vala
+++ b/vala/valablock.vala
@@ -99,6 +99,11 @@ public class Vala.Block : Symbol, Statement {
local_variables.add (local);
}
+ public void add_variable_override (Variable local, LocalVariable replacement) {
+ local_variables.add (replacement);
+ scope.add (local.name, replacement);
+ }
+
public void remove_local_variable (LocalVariable local) {
local_variables.remove (local);
}
diff --git a/vala/valaifstatement.vala b/vala/valaifstatement.vala
index e6f602de1..16929c442 100644
--- a/vala/valaifstatement.vala
+++ b/vala/valaifstatement.vala
@@ -121,6 +121,33 @@ public class Vala.IfStatement : CodeNode, Statement {
condition.check (context);
+ // chech if this statement is used for "type narrowing"
+ unowned TypeCheck? type_check = null;
+ unowned Block? narrowed_block = null;
+ unowned Variable? narrowed_var = null;
+ if (condition is UnaryExpression && ((UnaryExpression) condition).operator ==
UnaryOperator.LOGICAL_NEGATION) {
+ unowned Expression inner = ((UnaryExpression) condition).inner;
+ if (inner is TypeCheck) {
+ type_check = (TypeCheck) inner;
+ narrowed_var = type_check.expression.symbol_reference as Variable;
+ narrowed_block = false_statement;
+ }
+ } else if (condition is TypeCheck) {
+ type_check = (TypeCheck) condition;
+ narrowed_var = type_check.expression.symbol_reference as Variable;
+ narrowed_block = true_statement;
+ }
+ if (narrowed_var != null) {
+ var narrowed_type = type_check.type_reference.copy ();
+ narrowed_type.value_owned = false;
+ narrowed_type.nullable = false;
+ var initializer = new CastExpression (new MemberAccess.simple (narrowed_var.name,
type_check.source_reference), narrowed_type, type_check.source_reference);
+ var local = new LocalVariable (narrowed_type, "_%s_as_%s".printf (narrowed_var.name,
narrowed_type.to_string ()), initializer, type_check.source_reference);
+ narrowed_block.insert_statement (0, new DeclarationStatement (local,
source_reference));
+ narrowed_block.add_variable_override (narrowed_var, local);
+ local.check (context);
+ }
+
true_statement.check (context);
if (false_statement != null) {
false_statement.check (context);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]