[vala/wip/issue/767: 7/7] WIP Extend silent-cast support to type with known type signatures



commit 675778a1fb18f8b16682a43d83bb0da73365c09c
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Thu Mar 21 22:19:26 2019 +0100

    WIP Extend silent-cast support to type with known type signatures

 codegen/valagvariantmodule.vala                | 72 ++++++++++++++++++--------
 tests/basic-types/gvariants-unboxing-safe.vala |  7 +++
 tests/semantic/cast-gvariant-unsupported.test  |  2 +-
 vala/valacastexpression.vala                   |  4 +-
 vala/valasemanticanalyzer.vala                 |  5 --
 5 files changed, 59 insertions(+), 31 deletions(-)
---
diff --git a/codegen/valagvariantmodule.vala b/codegen/valagvariantmodule.vala
index 223302aa0..53639021e 100644
--- a/codegen/valagvariantmodule.vala
+++ b/codegen/valagvariantmodule.vala
@@ -160,32 +160,58 @@ public class Vala.GVariantModule : GAsyncModule {
 
                push_function (cfunc);
 
-               CCodeExpression func_result = deserialize_expression (target_type, new CCodeIdentifier 
("value"), new CCodeIdentifier ("*result"));
-               if (target_type.is_real_non_null_struct_type ()) {
-                       ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
-               } else {
-                       if (expr.is_silent_cast && SemanticAnalyzer.is_gvariant_basic_type (target_type)) {
-                               var ccheck = new CCodeFunctionCall (new CCodeIdentifier 
("g_variant_is_of_type"));
-                               ccheck.add_argument (new CCodeIdentifier ("value"));
-                               BasicTypeInfo basic_type;
-                               get_basic_type_info (target_type.get_type_signature (), out basic_type);
-                               ccheck.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_" + 
basic_type.type_name.ascii_up ()));
-                               ccode.open_if (ccheck);
-                               if (basic_type.is_string) {
-                                       ccode.add_return (func_result);
-                               } else {
-                                       var temp_type = expr.target_type.copy ();
-                                       temp_type.nullable = false;
-                                       var temp_value = create_temp_value (temp_type, false, expr);
-                                       store_value (temp_value, new GLibValue (temp_type, func_result), 
expr.source_reference);
-                                       ccode.add_return (get_cvalue_ (transform_value (temp_value, 
expr.target_type, expr)));
-                               }
-                               ccode.add_else ();
-                               ccode.add_return (new CCodeConstant ("NULL"));
-                               ccode.close ();
+               CCodeExpression type_expr = null;
+               BasicTypeInfo basic_type = {};
+               bool is_basic_type = false;
+               if (expr.is_silent_cast) {
+                       var signature = target_type.get_type_signature ();
+                       is_basic_type = get_basic_type_info (signature, out basic_type);
+                       var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_is_of_type"));
+                       ccheck.add_argument (new CCodeIdentifier ("value"));
+                       if (is_basic_type) {
+                               type_expr = new CCodeIdentifier ("G_VARIANT_TYPE_" + 
basic_type.type_name.ascii_up ());
                        } else {
+                               var gvariant_type_type = new ObjectType ((Class) root_symbol.scope.lookup 
("GLib").scope.lookup ("VariantType"));
+                               var type_temp = get_temp_variable (gvariant_type_type, true, expr, true);
+                               emit_temp_var (type_temp);
+                               type_expr = new CCodeFunctionCall (new CCodeIdentifier 
("g_variant_type_new"));
+                               ((CCodeFunctionCall) type_expr).add_argument (new CCodeIdentifier 
("\"%s\"".printf (signature)));
+                               store_value (get_local_cvalue (type_temp), new GLibValue (gvariant_type_type, 
type_expr), expr.source_reference);
+                               type_expr = get_variable_cexpression (type_temp.name);
+                       }
+                       ccheck.add_argument (type_expr);
+                       ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new 
CCodeIdentifier ("value"), ccheck));
+               }
+
+               CCodeExpression func_result = deserialize_expression (target_type, new CCodeIdentifier 
("value"), new CCodeIdentifier ("*result"));
+
+               if (expr.is_silent_cast) {
+                       if (is_basic_type && basic_type.is_string) {
                                ccode.add_return (func_result);
+                       } else {
+                               if (!is_basic_type) {
+                                       var type_free = new CCodeFunctionCall (new CCodeIdentifier 
("g_variant_type_free"));
+                                       type_free.add_argument (type_expr);
+                                       ccode.add_expression (type_free);
+                               }
+                               var temp_type = expr.target_type.copy ();
+                               temp_type.nullable = false;
+                               var temp_value = create_temp_value (temp_type, false, expr);
+                               store_value (temp_value, new GLibValue (temp_type, func_result), 
expr.source_reference);
+                               ccode.add_return (get_cvalue_ (transform_value (temp_value, expr.target_type, 
expr)));
                        }
+                       ccode.add_else ();
+                       if (!is_basic_type) {
+                               var type_free = new CCodeFunctionCall (new CCodeIdentifier 
("g_variant_type_free"));
+                               type_free.add_argument (type_expr);
+                               ccode.add_expression (type_free);
+                       }
+                       ccode.add_return (new CCodeConstant ("NULL"));
+                       ccode.close ();
+               } else if (target_type.is_real_non_null_struct_type ()) {
+                       ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
+               } else {
+                       ccode.add_return (func_result);
                }
 
                pop_function ();
diff --git a/tests/basic-types/gvariants-unboxing-safe.vala b/tests/basic-types/gvariants-unboxing-safe.vala
index 55e4eca45..43598d2b5 100644
--- a/tests/basic-types/gvariants-unboxing-safe.vala
+++ b/tests/basic-types/gvariants-unboxing-safe.vala
@@ -28,4 +28,11 @@ void main () {
                int32? i32 = v as int32;
                assert (i32 == null);
        }
+
+       v = new Variant.strv ({ "foo", "bar", "manam" });
+       {
+               string[]? sa = v as string[];
+               assert (sa != null);
+               assert (sa[2] == "manam");
+       }
 }
diff --git a/tests/semantic/cast-gvariant-unsupported.test b/tests/semantic/cast-gvariant-unsupported.test
index 80abaac67..2e4ed2d3e 100644
--- a/tests/semantic/cast-gvariant-unsupported.test
+++ b/tests/semantic/cast-gvariant-unsupported.test
@@ -2,5 +2,5 @@ Invalid Code
 
 void main () {
        Variant? v = null;
-       string[]? array = v as string[];
+       Object? array = v as Object;
 }
diff --git a/vala/valacastexpression.vala b/vala/valacastexpression.vala
index e1a4dc7ab..63e356155 100644
--- a/vala/valacastexpression.vala
+++ b/vala/valacastexpression.vala
@@ -184,8 +184,8 @@ public class Vala.CastExpression : Expression {
                    && is_gvariant (context, inner.value_type) && !is_gvariant (context, value_type)) {
                        // GVariant unboxing returns owned value
                        value_type.value_owned = true;
-                       if (is_silent_cast && !SemanticAnalyzer.is_gvariant_basic_type (value_type)) {
-                               Report.error (source_reference, "Silent casts of `GLib.Variant' is only 
supported for basic types");
+                       if (value_type.get_type_signature () == null) {
+                               Report.error (source_reference, "Casting of `GLib.Variant' to `%s' is not 
supported".printf (value_type.to_qualified_string ()));
                        }
                }
 
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 65bce9014..485ab222d 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -747,11 +747,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return true;
        }
 
-       public static bool is_gvariant_basic_type (DataType type) {
-               const string[] GVARIANT_BASIC_TYPES = { "y", "b", "n", "q", "i", "u", "x", "t", "d", "s", 
"o", "g" };
-               return type.get_type_signature () in GVARIANT_BASIC_TYPES;
-       }
-
        private static DataType? get_instance_base_type (DataType instance_type, DataType base_type, CodeNode 
node_reference) {
                // construct a new type reference for the base type with correctly linked type arguments
                DataType instance_base_type;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]