From fd83c9fba73965c8de04f058779fdee0f30cd971 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=BCrg=20Billeter?= Date: Sun, 11 Mar 2007 22:17:06 +0000 Subject: [PATCH] resolve generic return values fix check for generic method parameters to MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 2007-03-11 Jürg Billeter * 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 | 16 +++ vala/vala/valaclassregisterfunction.vala | 8 +- vala/vala/valacodegenerator.vala | 7 +- vala/vala/valainterface.vala | 13 ++- vala/vala/valainterfaceregisterfunction.vala | 6 +- vala/vala/valainvokable.vala | 4 +- vala/vala/valamemberaccess.vala | 6 +- vala/vala/valamemorymanager.vala | 58 +++++++++- vala/vala/valasemanticanalyzer.vala | 106 ++++++++++++++++--- vala/vala/valatyperegisterfunction.vala | 11 +- 10 files changed, 208 insertions(+), 27 deletions(-) diff --git a/vala/ChangeLog b/vala/ChangeLog index dddffbc3c..be1c86599 100644 --- a/vala/ChangeLog +++ b/vala/ChangeLog @@ -1,3 +1,19 @@ +2007-03-11 Jürg Billeter + + * 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 * ccode/valaccodecastexpression.vala: correct bracketing in cast diff --git a/vala/vala/valaclassregisterfunction.vala b/vala/vala/valaclassregisterfunction.vala index 0b29300be..c6fc43a85 100644 --- a/vala/vala/valaclassregisterfunction.vala +++ b/vala/vala/valaclassregisterfunction.vala @@ -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)); } diff --git a/vala/vala/valacodegenerator.vala b/vala/vala/valacodegenerator.vala index cffc1b32f..7bef9255e 100644 --- a/vala/vala/valacodegenerator.vala +++ b/vala/vala/valacodegenerator.vala @@ -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; } diff --git a/vala/vala/valainterface.vala b/vala/vala/valainterface.vala index 30dc57980..e380d3121 100644 --- a/vala/vala/valainterface.vala +++ b/vala/vala/valainterface.vala @@ -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; + } } diff --git a/vala/vala/valainterfaceregisterfunction.vala b/vala/vala/valainterfaceregisterfunction.vala index 42fcbafbe..cda7b6b61 100644 --- a/vala/vala/valainterfaceregisterfunction.vala +++ b/vala/vala/valainterfaceregisterfunction.vala @@ -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"; } diff --git a/vala/vala/valainvokable.vala b/vala/vala/valainvokable.vala index 21fe9271e..f5dc56dc0 100644 --- a/vala/vala/valainvokable.vala +++ b/vala/vala/valainvokable.vala @@ -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. * diff --git a/vala/vala/valamemberaccess.vala b/vala/vala/valamemberaccess.vala index 30aff0a49..d8052ee2d 100644 --- a/vala/vala/valamemberaccess.vala +++ b/vala/vala/valamemberaccess.vala @@ -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); } diff --git a/vala/vala/valamemorymanager.vala b/vala/vala/valamemorymanager.vala index 00c5ef990..969119569 100644 --- a/vala/vala/valamemorymanager.vala +++ b/vala/vala/valamemorymanager.vala @@ -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 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; } } diff --git a/vala/vala/valasemanticanalyzer.vala b/vala/vala/valasemanticanalyzer.vala index 8bacce881..993cebe0f 100644 --- a/vala/vala/valasemanticanalyzer.vala +++ b/vala/vala/valasemanticanalyzer.vala @@ -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 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 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 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 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; } diff --git a/vala/vala/valatyperegisterfunction.vala b/vala/vala/valatyperegisterfunction.vala index 333ec0d91..95501c628 100644 --- a/vala/vala/valatyperegisterfunction.vala +++ b/vala/vala/valatyperegisterfunction.vala @@ -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 ())); @@ -76,6 +76,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. * -- 2.47.3