Commit fd83c9fb authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter

resolve generic return values fix check for generic method parameters to

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
parent 1ed98e02
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
......
/* 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));
}
......
......@@ -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;
}
......
/* 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;
}
}
......@@ -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";
}
......
/* 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.
*
......
/* 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);
}
......
......@@ -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;
}
}
......
......@@ -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;
}
......
/* 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.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment