[vala/wip/issue/894: 75/76] vala: Add support for type narrowing
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/issue/894: 75/76] vala: Add support for type narrowing
- Date: Thu, 15 Oct 2020 11:32:19 +0000 (UTC)
commit 6d827062bd4d6cc00ad8c0f18492e8497e70dba3
Author: Rico Tzschichholz <ricotz ubuntu com>
Date: Tue Aug 11 15:22:21 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
codegen/valaccodememberaccessmodule.vala | 8 +++++
tests/Makefile.am | 1 +
tests/objects/type-narrowing.vala | 58 ++++++++++++++++++++++++++++++++
vala/valamemberaccess.vala | 4 +++
vala/valasemanticanalyzer.vala | 46 +++++++++++++++++++++++++
5 files changed, 117 insertions(+)
---
diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala
index f46ea9dfd..bf44ccb74 100644
--- a/codegen/valaccodememberaccessmodule.vala
+++ b/codegen/valaccodememberaccessmodule.vala
@@ -400,6 +400,14 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
expr.target_value = load_parameter (param, expr);
}
}
+
+ // Add cast for narrowed type access of variables if needed
+ if (expr.symbol_reference is Variable) {
+ unowned GLibValue cvalue = (GLibValue) expr.target_value;
+ if (cvalue.value_type.type_symbol != expr.value_type.type_symbol) {
+ cvalue.cvalue = new CCodeCastExpression (cvalue.cvalue, get_ccode_name
(expr.value_type));
+ }
+ }
}
/* Returns lvalue access to the given local variable */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c6865db09..9e22e1bf3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -454,6 +454,7 @@ TESTS = \
objects/signals-prototype-access-invalid-2.test \
objects/signals-struct-return.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..47997d141
--- /dev/null
+++ b/tests/objects/type-narrowing.vala
@@ -0,0 +1,58 @@
+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;
+ }
+}
+
+class Manam : Bar {
+ public Manam (string s) {
+ base (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);
+ }
+ {
+ Bar bar = new Manam ("manam");
+ if (bar is Manam) {
+ assert (bar.str == "manam");
+ bar = new Bar ("bar");
+ }
+ assert (bar.str == "bar");
+ }
+}
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index b1cc20ada..ffde65018 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -986,6 +986,10 @@ public class Vala.MemberAccess : Expression {
var parent_type = SemanticAnalyzer.get_data_type_for_symbol
(symbol_reference.parent_symbol);
inner.target_type = parent_type.get_actual_type (inner.value_type, null,
this);
}
+
+ if (inner == null) {
+ value_type = SemanticAnalyzer.get_narrowed_type (this);
+ }
}
if (value_type != null) {
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 8242efd35..7fde2a23a 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -942,6 +942,52 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
return null;
}
+ public static DataType get_narrowed_type (MemberAccess member_access) {
+ unowned Variable? variable = member_access.symbol_reference as Variable;
+ if (variable == null) {
+ return member_access.value_type;
+ }
+
+ if (!(member_access.parent_node is MemberAccess)) {
+ return member_access.value_type;
+ }
+
+ bool is_negation = false;
+ unowned CodeNode? parent = member_access.parent_node;
+ unowned IfStatement? if_statement = null;
+ while (parent != null && !(parent is Method)) {
+ if (parent is TypeCheck) {
+ parent = null;
+ break;
+ }
+ if (parent.parent_node is IfStatement) {
+ if_statement = (IfStatement) parent.parent_node;
+ is_negation = if_statement.false_statement == parent;
+ break;
+ }
+ parent = parent.parent_node;
+ }
+
+ if (if_statement != null) {
+ unowned Expression expr = if_statement.condition;
+ if (expr is UnaryExpression && ((UnaryExpression) expr).operator ==
UnaryOperator.LOGICAL_NEGATION) {
+ expr = ((UnaryExpression) expr).inner;
+ is_negation = !is_negation;
+ }
+ unowned TypeCheck? type_check = expr as TypeCheck;
+ if (!is_negation && type_check != null) {
+ var narrowed_type = type_check.type_reference.copy ();
+ narrowed_type.value_owned = member_access.value_type.value_owned;
+ if (variable == type_check.expression.symbol_reference
+ && narrowed_type.type_symbol != member_access.value_type.type_symbol) {
+ return narrowed_type;
+ }
+ }
+ }
+
+ return member_access.value_type;
+ }
+
public static DataType get_actual_type (DataType? derived_instance_type, List<DataType>?
method_type_arguments, GenericType generic_type, CodeNode? node_reference) {
DataType actual_type = null;
if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]