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

Improve handling of generic values, fixes bug 562460

2008-11-28  Jürg Billeter  <j@bitron.ch>

	* vala/valadatatype.vala:
	* vala/valaexpression.vala:
	* vala/valaintegertype.vala:
	* vala/valamemberaccess.vala:
	* vala/valamethodcall.vala:
	* vala/valasemanticanalyzer.vala:
	* vala/valavaluetype.vala:
	* gobject/valaccodebasemodule.vala:
	* gobject/valaccodecontrolflowmodule.vala:

	Improve handling of generic values, fixes bug 562460

svn path=/trunk/; revision=2067
parent 4b4f30b4
2008-11-28 Jürg Billeter <j@bitron.ch>
* vala/valadatatype.vala:
* vala/valaexpression.vala:
* vala/valaintegertype.vala:
* vala/valamemberaccess.vala:
* vala/valamethodcall.vala:
* vala/valasemanticanalyzer.vala:
* vala/valavaluetype.vala:
* gobject/valaccodebasemodule.vala:
* gobject/valaccodecontrolflowmodule.vala:
Improve handling of generic values, fixes bug 562460
2008-11-28 Jürg Billeter <j@bitron.ch>
* vala/valabinaryexpression.vala:
......
......@@ -2092,8 +2092,22 @@ public class Vala.CCodeBaseModule : CCodeModule {
public override void visit_expression (Expression expr) {
if (expr.ccodenode != null && !expr.lvalue) {
if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
if (expr.formal_value_type.type_parameter.parent_symbol != garray_type) {
// GArray doesn't use pointer-based generics
expr.ccodenode = convert_from_generic_pointer ((CCodeExpression) expr.ccodenode, expr.value_type);
}
}
// memory management, implicit casts, and boxing/unboxing
expr.ccodenode = transform_expression ((CCodeExpression) expr.ccodenode, expr.value_type, expr.target_type, expr);
if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
if (expr.formal_target_type.type_parameter.parent_symbol != garray_type) {
// GArray doesn't use pointer-based generics
expr.ccodenode = convert_to_generic_pointer ((CCodeExpression) expr.ccodenode, expr.target_type);
}
}
}
}
......@@ -3005,12 +3019,6 @@ public class Vala.CCodeBaseModule : CCodeModule {
cexpr = get_implicit_cast_expression (cexpr, expression_type, target_type, expr);
}
if (expression_type.is_type_argument) {
cexpr = convert_from_generic_pointer (cexpr, target_type);
} else if (target_type.is_type_argument) {
cexpr = convert_to_generic_pointer (cexpr, expression_type);
}
if (target_type.value_owned && (!expression_type.value_owned || boxing || unboxing)) {
// need to copy value
if (requires_copy (target_type) && !(expression_type is NullType)) {
......
......@@ -429,7 +429,7 @@ public class Vala.CCodeControlFlowModule : CCodeMethodModule {
var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
element_data_type.value_owned = false;
element_data_type.is_type_argument = true;
element_expr = convert_from_generic_pointer (element_expr, element_data_type);
element_expr = transform_expression (element_expr, element_data_type, stmt.type_reference);
var cfrag = new CCodeFragment ();
......@@ -472,6 +472,7 @@ public class Vala.CCodeControlFlowModule : CCodeMethodModule {
var element_type = SemanticAnalyzer.get_actual_type (stmt.collection.value_type, (GenericType) get_method.return_type, stmt);
element_expr = convert_from_generic_pointer (element_expr, element_type);
element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
var cfrag = new CCodeFragment ();
......
......@@ -39,11 +39,6 @@ public abstract class Vala.DataType : CodeNode {
*/
public bool nullable { get; set; }
/**
* Specifies that this type is a generic type argument.
*/
public bool is_type_argument { get; set; }
/**
* The referred data type.
*/
......@@ -481,4 +476,26 @@ public abstract class Vala.DataType : CodeNode {
}
return false;
}
public DataType get_actual_type (DataType? derived_instance_type, CodeNode node_reference) {
if (derived_instance_type == null) {
return this;
}
DataType result = this;
if (result is GenericType) {
result = SemanticAnalyzer.get_actual_type (derived_instance_type, (GenericType) result, node_reference);
}
if (result.type_argument_list != null) {
// recursely get actual types for type arguments
result = result.copy ();
for (int i = 0; i < result.type_argument_list.size; i++) {
result.type_argument_list[i] = result.type_argument_list[i].get_actual_type (derived_instance_type, node_reference);
}
}
return result;
}
}
......@@ -33,14 +33,18 @@ public abstract class Vala.Expression : CodeNode {
* The semantic analyzer computes this value.
*/
public DataType value_type { get; set; }
public DataType? formal_value_type { get; set; }
/*
* The static type this expression is expected to have.
*
* The semantic analyzer computes this value, lambda expressions use it.
*/
public DataType target_type { get; set; }
public DataType? formal_target_type { get; set; }
/**
* The symbol this expression refers to.
*/
......
......@@ -37,9 +37,7 @@ public class Vala.IntegerType : ValueType {
}
public override DataType copy () {
var type = new IntegerType (type_symbol, literal_value, literal_type_name);
type.is_type_argument = is_type_argument;
return type;
return new IntegerType (type_symbol, literal_value, literal_type_name);
}
public override bool compatible (DataType target_type) {
......
......@@ -487,16 +487,11 @@ public class Vala.MemberAccess : Expression {
inner.symbol_reference = this_parameter;
}
value_type = analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
// resolve generic return values
if (value_type is GenericType) {
if (inner != null) {
value_type = analyzer.get_actual_type (inner.value_type, (GenericType) value_type, this);
if (value_type == null) {
return false;
}
}
formal_value_type = analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
if (inner != null && formal_value_type != null) {
value_type = formal_value_type.get_actual_type (inner.value_type, this);
} else {
value_type = formal_value_type;
}
if (symbol_reference is Method) {
......
......@@ -134,6 +134,9 @@ public class Vala.MethodCall : Expression {
return false;
}
// type of target object
DataType target_object_type = null;
if (call is MemberAccess) {
var ma = (MemberAccess) call;
if (ma.prototype_access) {
......@@ -141,6 +144,10 @@ public class Vala.MethodCall : Expression {
Report.error (source_reference, "Access to instance member `%s' denied".printf (call.symbol_reference.get_full_name ()));
return false;
}
if (ma.inner != null) {
target_object_type = ma.inner.value_type;
}
}
var mtype = call.value_type;
......@@ -220,16 +227,8 @@ public class Vala.MethodCall : Expression {
Expression arg = arg_it.get ();
/* store expected type for callback parameters */
arg.target_type = param.parameter_type;
// resolve generic type parameters
var ma = call as MemberAccess;
if (arg.target_type is GenericType) {
if (ma != null && ma.inner != null) {
arg.target_type = analyzer.get_actual_type (ma.inner.value_type, (GenericType) arg.target_type, arg);
assert (arg.target_type != null);
}
}
arg.formal_target_type = param.parameter_type;
arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, this);
last_arg = arg;
}
......@@ -373,9 +372,7 @@ public class Vala.MethodCall : Expression {
arg.check (analyzer);
}
DataType ret_type;
ret_type = mtype.get_return_type ();
DataType ret_type = mtype.get_return_type ();
params = mtype.get_parameters ();
if (ret_type is VoidType) {
......@@ -391,29 +388,8 @@ public class Vala.MethodCall : Expression {
}
}
// resolve generic return values
var ma = call as MemberAccess;
if (ret_type is GenericType) {
if (ma != null && ma.inner != null) {
ret_type = analyzer.get_actual_type (ma.inner.value_type, (GenericType) ret_type, this);
if (ret_type == null) {
return false;
}
}
}
Gee.List<DataType> resolved_type_args = new ArrayList<DataType> ();
foreach (DataType type_arg in ret_type.get_type_arguments ()) {
if (type_arg is GenericType && ma != null && ma.inner != null) {
resolved_type_args.add (analyzer.get_actual_type (ma.inner.value_type, (GenericType) type_arg, this));
} else {
resolved_type_args.add (type_arg);
}
}
ret_type = ret_type.copy ();
ret_type.remove_all_type_arguments ();
foreach (DataType resolved_type_arg in resolved_type_args) {
ret_type.add_type_argument (resolved_type_arg);
}
formal_value_type = ret_type;
value_type = formal_value_type.get_actual_type (target_object_type, this);
if (mtype is MethodType) {
var m = ((MethodType) mtype).method_symbol;
......@@ -426,8 +402,6 @@ public class Vala.MethodCall : Expression {
}
}
value_type = ret_type;
analyzer.check_arguments (this, mtype, params, get_argument_list ());
return !error;
......
......@@ -569,10 +569,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
return generic_type;
}
actual_type = actual_type.copy ();
if (!(derived_instance_type.data_type != null && derived_instance_type.data_type.get_full_name () == "GLib.Array")) {
// GArray doesn't use pointer-based generics
actual_type.is_type_argument = true;
}
actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
return actual_type;
}
......
......@@ -43,7 +43,6 @@ public class Vala.ValueType : DataType {
result.nullable = nullable;
result.is_dynamic = is_dynamic;
result.floating_reference = floating_reference;
result.is_type_argument = is_type_argument;
foreach (DataType arg in get_type_arguments ()) {
result.add_type_argument (arg.copy ());
......
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