resolve generic return values fix check for generic method parameters to
authorJürg Billeter <j@bitron.ch>
Sun, 11 Mar 2007 22:17:06 +0000 (22:17 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sun, 11 Mar 2007 22:17:06 +0000 (22:17 +0000)
2007-03-11  Jürg Billeter  <j@bitron.ch>

* vala/valasemanticanalyzer.vala: resolve generic return values
* vala/valamemorymanager.vala: fix check for generic method parameters
  to support derived types
* vala/valainterface.vala: implement get_type_parameter_index
* vala/valamemberaccess.vala: visit type arguments
* vala/valaclassregisterfunction.vala,
  vala/valainterfaceregisterfunction.vala,
  vala/valatyperegisterfunction.vala: pass base_init function pointer
  for interfaces
* vala/valacodegenerator.vala: fix initialization check in interface
  base_init function
* vala/valasemanticanalyzer.vala: fix prerequisite check to also accept
  derived types of prerequisites

svn path=/trunk/; revision=234

vala/ChangeLog
vala/vala/valaclassregisterfunction.vala
vala/vala/valacodegenerator.vala
vala/vala/valainterface.vala
vala/vala/valainterfaceregisterfunction.vala
vala/vala/valainvokable.vala
vala/vala/valamemberaccess.vala
vala/vala/valamemorymanager.vala
vala/vala/valasemanticanalyzer.vala
vala/vala/valatyperegisterfunction.vala

index dddffbc..be1c865 100644 (file)
@@ -1,3 +1,19 @@
+2007-03-11  Jürg Billeter  <j@bitron.ch>
+
+       * vala/valasemanticanalyzer.vala: resolve generic return values
+       * vala/valamemorymanager.vala: fix check for generic method parameters
+         to support derived types
+       * vala/valainterface.vala: implement get_type_parameter_index
+       * vala/valamemberaccess.vala: visit type arguments
+       * vala/valaclassregisterfunction.vala,
+         vala/valainterfaceregisterfunction.vala,
+         vala/valatyperegisterfunction.vala: pass base_init function pointer
+         for interfaces
+       * vala/valacodegenerator.vala: fix initialization check in interface
+         base_init function
+       * vala/valasemanticanalyzer.vala: fix prerequisite check to also accept
+         derived types of prerequisites
+
 2007-03-10  Jürg Billeter  <j@bitron.ch>
 
        * ccode/valaccodecastexpression.vala: correct bracketing in cast
index 0b29300..c6fc43a 100644 (file)
@@ -1,6 +1,6 @@
 /* valaclassregisterfunction.vala
  *
- * Copyright (C) 2006  Jürg Billeter
+ * Copyright (C) 2006-2007  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -48,7 +48,11 @@ public class Vala.ClassRegisterFunction : TypeRegisterFunction {
        public override ref string! get_type_struct_name () {
                return "%sClass".printf (class_reference.get_cname ());
        }
-       
+
+       public override ref string! get_base_init_func_name () {
+               return "NULL";
+       }
+
        public override ref string! get_class_init_func_name () {
                return "%s_class_init".printf (class_reference.get_lower_case_cname (null));
        }
index cffc1b3..7bef925 100644 (file)
@@ -961,6 +961,7 @@ public class Vala.CodeGenerator : CodeVisitor {
                /* make sure not to run the initialization code twice */
                base_init.block = new CCodeBlock ();
                var decl = new CCodeDeclaration (bool_type.get_cname ());
+               decl.modifiers |= CCodeModifiers.STATIC;
                decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("initialized", new CCodeConstant ("FALSE")));
                base_init.block.add_statement (decl);
                var cif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("initialized")), init_block);
@@ -1641,7 +1642,8 @@ public class Vala.CodeGenerator : CodeVisitor {
                var params = sig.get_parameters ();
                
                if (prefix == null) {
-                       if (predefined_marshal_list.lookup (signature) != null) {
+                       // FIXME remove equality check with cast in next revision
+                       if (predefined_marshal_list.lookup (signature) != (bool) null) {
                                prefix = "g_cclosure_marshal";
                        } else {
                                prefix = "g_cclosure_user_marshal";
@@ -1714,7 +1716,8 @@ public class Vala.CodeGenerator : CodeVisitor {
                
                /* check whether a signal with the same signature already exists for this source file (or predefined) */
                signature = get_signal_signature (sig);
-               if (predefined_marshal_list.lookup (signature) != null || user_marshal_list.lookup (signature) != null) {
+               // FIXME remove equality checks with cast in next revision
+               if (predefined_marshal_list.lookup (signature) != (bool) null || user_marshal_list.lookup (signature) != (bool) null) {
                        return;
                }
                
index 30dc579..e380d31 100644 (file)
@@ -1,6 +1,6 @@
 /* valainterface.vala
  *
- * Copyright (C) 2006  Jürg Billeter
+ * Copyright (C) 2006-2007  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -277,4 +277,15 @@ public class Vala.Interface : DataType {
                
                return type_id;
        }
+
+       public override int get_type_parameter_index (string! name) {
+               int i = 0;
+               foreach (TypeParameter parameter in type_parameters) {
+                       if (parameter.name == name) {
+                               return i;
+                       }
+                       i++;
+               }
+               return -1;
+       }
 }
index 42fcbaf..cda7b6b 100644 (file)
@@ -43,7 +43,11 @@ public class Vala.InterfaceRegisterFunction : TypeRegisterFunction {
        public override ref string! get_type_struct_name () {
                return interface_reference.get_type_cname ();
        }
-       
+
+       public override ref string! get_base_init_func_name () {
+               return "%s_base_init".printf (interface_reference.get_lower_case_cname (null));
+       }
+
        public override ref string! get_class_init_func_name () {
                return "NULL";
        }
index 21fe927..f5dc56d 100644 (file)
@@ -1,6 +1,6 @@
 /* valainvokable.vala
  *
- * Copyright (C) 2006  Jürg Billeter
+ * Copyright (C) 2006-2007  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,7 @@ using GLib;
 /**
  * Represents a possibly invokable code object.
  */
-public interface Vala.Invokable {
+public interface Vala.Invokable /* : CodeNode */ {
        /**
         * Returns whether this code object is invokable.
         *
index 30aff0a..d8052ee 100644 (file)
@@ -1,6 +1,6 @@
 /* valamemberaccess.vala
  *
- * Copyright (C) 2006  Jürg Billeter
+ * Copyright (C) 2006-2007  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -90,6 +90,10 @@ public class Vala.MemberAccess : Expression {
                if (inner != null) {
                        inner.accept (visitor);
                }
+               
+               foreach (TypeReference type_arg in type_argument_list) {
+                       type_arg.accept (visitor);
+               }
 
                visitor.visit_member_access (this);
        }
index 00c5ef9..9691195 100644 (file)
@@ -156,14 +156,64 @@ public class Vala.MemoryManager : CodeVisitor {
                                    || param.type_reference.type_parameter != null)) {
                                        bool is_ref = param.type_reference.takes_ownership;
                                        if (is_ref && param.type_reference.type_parameter != null) {
+                                               // TODO move this to semantic analyzer
                                                if (expr.call is MemberAccess) {
-                                                       var instance_type = ((MemberAccess) expr.call).inner.static_type;
-                                                       var param_index = instance_type.data_type.get_type_parameter_index (param.type_reference.type_parameter.name);
+                                                       var ma = (MemberAccess) expr.call;
+                                                       ref TypeReference instance_type = ma.inner.static_type;
+                                                       // trace type arguments back to the datatype where the method has been declared
+                                                       while (instance_type.data_type != msym.parent_symbol.node) {
+                                                               List<weak TypeReference> base_types = null;
+                                                               if (instance_type.data_type is Class) {
+                                                                       var cl = (Class) instance_type.data_type;
+                                                                       base_types = cl.get_base_types ();
+                                                               } else if (instance_type.data_type is Interface) {
+                                                                       var iface = (Interface) instance_type.data_type;
+                                                                       base_types = iface.get_prerequisites ();
+                                                               } else {
+                                                                       Report.error (expr.source_reference, "internal error: unsupported generic type");
+                                                                       expr.error = true;
+                                                                       return;
+                                                               }
+                                                               foreach (TypeReference base_type in base_types) {
+                                                                       if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type.symbol, msym.name) != null) {
+                                                                               // construct a new type reference for the base type with correctly linked type arguments
+                                                                               var instance_base_type = new TypeReference ();
+                                                                               instance_base_type.data_type = base_type.data_type;
+                                                                               foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
+                                                                                       if (type_arg.type_parameter != null) {
+                                                                                               // link to type argument of derived type
+                                                                                               int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
+                                                                                               if (param_index == -1) {
+                                                                                                       Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
+                                                                                                       expr.error = true;
+                                                                                                       return;
+                                                                                               }
+                                                                                               type_arg = instance_type.get_type_arguments ().nth_data (param_index);
+                                                                                       }
+                                                                                       instance_base_type.add_type_argument (type_arg);
+                                                                               }
+                                                                               instance_type = instance_base_type;
+                                                                       }
+                                                               }
+                                                       }
+                                                       if (instance_type.data_type != msym.parent_symbol.node) {
+                                                               Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet");
+                                                               expr.error = true;
+                                                               return;
+                                                       }
+                                                       int param_index = instance_type.data_type.get_type_parameter_index (param.type_reference.type_parameter.name);
                                                        if (param_index == -1) {
-                                                               Report.error (arg.source_reference, "Internal Error: No actual parameter found for `%s' in `%s'".printf (param.name, instance_type.data_type.symbol.get_full_name ()));
+                                                               Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (param.type_reference.type_parameter.name));
+                                                               expr.error = true;
+                                                               return;
+                                                       }
+                                                       var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
+                                                       if (param_type == null) {
+                                                               Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (param.type_reference.type_parameter.name));
+                                                               expr.error = true;
                                                                return;
                                                        }
-                                                       is_ref = ((TypeReference)instance_type.get_type_arguments ().nth_data (param_index)).takes_ownership;
+                                                       is_ref = param_type.takes_ownership;
                                                }
                                        }
                                        
index 8bacce8..993cebe 100644 (file)
@@ -138,25 +138,36 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return ret.reverse ();
        }
        
+       private bool class_is_a (Class! cl, DataType! t) {
+               if (cl == t) {
+                       return true;
+               }
+               
+               foreach (TypeReference base_type in cl.get_base_types ()) {
+                       if (base_type.data_type is Class) {
+                               if (class_is_a ((Class) base_type.data_type, t)) {
+                                       return true;
+                               }
+                       } else if (base_type.data_type == t) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+       
        public override void visit_end_class (Class! cl) {
                /* gather all prerequisites */
                List<DataType> prerequisites = null;
                foreach (TypeReference base_type in cl.get_base_types ()) {
                        if (base_type.data_type is Interface) {
-                               prerequisites.concat (get_all_prerequisites ((Interface)base_type.data_type));
+                               prerequisites.concat (get_all_prerequisites ((Interface) base_type.data_type));
                        }
                }
                /* check whether all prerequisites are met */
                List<string> missing_prereqs = null;
                foreach (DataType prereq in prerequisites) {
-                       bool found = false;
-                       foreach (TypeReference base_type in cl.get_base_types ()) {
-                               if (base_type.data_type == prereq) {
-                                       found = true;
-                                       break;
-                               }
-                       }
-                       if (!found) {
+                       if (!class_is_a (cl, prereq)) {
                                missing_prereqs.prepend (prereq.symbol.get_full_name ());
                        }
                }
@@ -949,7 +960,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return null;
        }
        
-       Symbol symbol_lookup_inherited (Symbol! sym, string! name) {
+       public static Symbol symbol_lookup_inherited (Symbol! sym, string! name) {
                var result = sym.lookup (name);
                if (result != null) {
                        return result;
@@ -1248,13 +1259,84 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                
                var msym = expr.call.symbol_reference;
                
-               TypeReference ret_type;
+               ref TypeReference ret_type;
                List<weak FormalParameter> params;
                
                if (msym.node is Invokable) {
                        var m = (Invokable) msym.node;
                        ret_type = m.get_return_type ();
                        params = m.get_parameters ();
+
+                       // resolve generic return values
+                       if (ret_type.type_parameter != null) {
+                               if (!(expr.call is MemberAccess)) {
+                                       Report.error (((CodeNode) m).source_reference, "internal error: unsupported generic return value");
+                                       expr.error = true;
+                                       return;
+                               }
+                               var ma = (MemberAccess) expr.call;
+                               if (ma.inner == null) {
+                                       // TODO resolve generic return values within the type hierarchy if possible
+                                       Report.error (expr.source_reference, "internal error: resolving generic return values within type hierarchy not supported yet");
+                                       expr.error = true;
+                                       return;
+                               } else {
+                                       ref TypeReference instance_type = ma.inner.static_type;
+                                       // trace type arguments back to the datatype where the method has been declared
+                                       while (instance_type.data_type != msym.parent_symbol.node) {
+                                               List<weak TypeReference> base_types = null;
+                                               if (instance_type.data_type is Class) {
+                                                       var cl = (Class) instance_type.data_type;
+                                                       base_types = cl.get_base_types ();
+                                               } else if (instance_type.data_type is Interface) {
+                                                       var iface = (Interface) instance_type.data_type;
+                                                       base_types = iface.get_prerequisites ();
+                                               } else {
+                                                       Report.error (expr.source_reference, "internal error: unsupported generic type");
+                                                       expr.error = true;
+                                                       return;
+                                               }
+                                               foreach (TypeReference base_type in base_types) {
+                                                       if (symbol_lookup_inherited (base_type.data_type.symbol, msym.name) != null) {
+                                                               // construct a new type reference for the base type with correctly linked type arguments
+                                                               var instance_base_type = new TypeReference ();
+                                                               instance_base_type.data_type = base_type.data_type;
+                                                               foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
+                                                                       if (type_arg.type_parameter != null) {
+                                                                               // link to type argument of derived type
+                                                                               int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
+                                                                               if (param_index == -1) {
+                                                                                       Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
+                                                                                       expr.error = true;
+                                                                                       return;
+                                                                               }
+                                                                               type_arg = instance_type.get_type_arguments ().nth_data (param_index);
+                                                                       }
+                                                                       instance_base_type.add_type_argument (type_arg);
+                                                               }
+                                                               instance_type = instance_base_type;
+                                                       }
+                                               }
+                                       }
+                                       if (instance_type.data_type != msym.parent_symbol.node) {
+                                               Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet");
+                                               expr.error = true;
+                                               return;
+                                       }
+                                       int param_index = instance_type.data_type.get_type_parameter_index (ret_type.type_parameter.name);
+                                       if (param_index == -1) {
+                                               Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (ret_type.type_parameter.name));
+                                               expr.error = true;
+                                               return;
+                                       }
+                                       ret_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
+                                       if (ret_type == null) {
+                                               Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (ret_type.type_parameter.name));
+                                               expr.error = true;
+                                               return;
+                                       }
+                               }
+                       }
                }
        
                expr.static_type = ret_type;
@@ -1350,7 +1432,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                var constructor = (Method) constructor_node;
                                if (!(constructor_node is CreationMethod)) {
                                        expr.error = true;
-                                       Report.error (expr.source_reference, "`%s' is not a construction method".printf (constructor.symbol.get_full_name ()));
+                                       Report.error (expr.source_reference, "`%s' is not a creation method".printf (constructor.symbol.get_full_name ()));
                                        return;
                                }
                                
index 333ec0d..95501c6 100644 (file)
@@ -1,6 +1,6 @@
 /* valatyperegisterfunction.vala
  *
- * Copyright (C) 2006  Jürg Billeter
+ * Copyright (C) 2006-2007  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -44,7 +44,7 @@ public abstract class Vala.TypeRegisterFunction : CCodeFunction {
                var type_init = new CCodeBlock ();
                var ctypedecl = new CCodeDeclaration ("const GTypeInfo");
                ctypedecl.modifiers = CCodeModifiers.STATIC;
-               ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("g_define_type_info", new CCodeConstant ("{ sizeof (%s), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) %s, (GClassFinalizeFunc) NULL, NULL, %s, 0, (GInstanceInitFunc) %s }".printf (get_type_struct_name (), get_class_init_func_name (), get_instance_struct_size (), get_instance_init_func_name ()))));
+               ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("g_define_type_info", new CCodeConstant ("{ sizeof (%s), (GBaseInitFunc) %s, (GBaseFinalizeFunc) NULL, (GClassInitFunc) %s, (GClassFinalizeFunc) NULL, NULL, %s, 0, (GInstanceInitFunc) %s }".printf (get_type_struct_name (), get_base_init_func_name (), get_class_init_func_name (), get_instance_struct_size (), get_instance_init_func_name ()))));
                type_init.add_statement (ctypedecl);
                var reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_static"));
                reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ()));
@@ -77,6 +77,13 @@ public abstract class Vala.TypeRegisterFunction : CCodeFunction {
        public abstract ref string! get_type_struct_name ();
 
        /**
+        * Returns the name of the base_init function in C code.
+        *
+        * @return C function name
+        */
+       public abstract ref string! get_base_init_func_name ();
+
+       /**
         * Returns the name of the class_init function in C code.
         *
         * @return C function name