Commit 223fcec2 authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter
Browse files

support element access for types implementing Gee.List or Gee.Map

2007-07-26  Juerg Billeter  <j@bitron.ch>

	* vala/valamemorymanager.vala, vala/valasemanticanalyzer.vala,
	  gobject/valacodegenerator.vala,
	  gobject/valacodegeneratorassignment.vala,
	  gobject/valacodegeneratorinvocationexpression.vala: support element
	  access for types implementing Gee.List or Gee.Map

svn path=/trunk/; revision=390
parent 2ebb31c9
2007-07-26 Jürg Billeter <j@bitron.ch>
* vala/valamemorymanager.vala, vala/valasemanticanalyzer.vala,
gobject/valacodegenerator.vala,
gobject/valacodegeneratorassignment.vala,
gobject/valacodegeneratorinvocationexpression.vala: support element
access for types implementing Gee.List or Gee.Map
2007-07-26 Jürg Billeter <j@bitron.ch>
* vala/valastruct.vala, gobject/valacodegeneratormethod.vala,
......
......@@ -95,12 +95,14 @@ public class Vala.CodeGenerator : CodeVisitor {
TypeReference string_type;
TypeReference float_type;
TypeReference double_type;
DataType list_type;
DataType slist_type;
DataType glist_type;
DataType gslist_type;
TypeReference mutex_type;
DataType type_module_type;
DataType iterable_type;
DataType iterator_type;
DataType list_type;
DataType map_type;
Method substring_method;
......@@ -236,8 +238,8 @@ public class Vala.CodeGenerator : CodeVisitor {
var glib_ns = root_symbol.scope.lookup ("GLib");
list_type = (DataType) glib_ns.scope.lookup ("List");
slist_type = (DataType) glib_ns.scope.lookup ("SList");
glist_type = (DataType) glib_ns.scope.lookup ("List");
gslist_type = (DataType) glib_ns.scope.lookup ("SList");
mutex_type = new TypeReference ();
mutex_type.data_type = (DataType) glib_ns.scope.lookup ("Mutex");
......@@ -259,6 +261,8 @@ public class Vala.CodeGenerator : CodeVisitor {
if (gee_ns != null) {
iterable_type = (DataType) gee_ns.scope.lookup ("Iterable");
iterator_type = (DataType) gee_ns.scope.lookup ("Iterator");
list_type = (DataType) gee_ns.scope.lookup ("List");
map_type = (DataType) gee_ns.scope.lookup ("Map");
}
/* we're only interested in non-pkg source files */
......@@ -1380,8 +1384,8 @@ public class Vala.CodeGenerator : CodeVisitor {
cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
cblock.add_statement (cfor);
}
} else if (stmt.collection.static_type.data_type == list_type ||
stmt.collection.static_type.data_type == slist_type) {
} else if (stmt.collection.static_type.data_type == glist_type ||
stmt.collection.static_type.data_type == gslist_type) {
var it_name = "%s_it".printf (stmt.variable_name);
var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ());
......@@ -1392,19 +1396,7 @@ public class Vala.CodeGenerator : CodeVisitor {
CCodeExpression element_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "data");
/* cast pointer to actual type if appropriate */
if (stmt.type_reference.data_type is Struct) {
var st = (Struct) stmt.type_reference.data_type;
if (st == uint_type.data_type) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
cconv.add_argument (element_expr);
element_expr = cconv;
} else if (st == bool_type.data_type || st.is_integer_type ()) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
cconv.add_argument (element_expr);
element_expr = cconv;
}
}
element_expr = convert_from_generic_pointer (element_expr, stmt.type_reference);
var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
......@@ -1438,19 +1430,7 @@ public class Vala.CodeGenerator : CodeVisitor {
get_ccall.add_argument (new CCodeIdentifier (it_name));
CCodeExpression element_expr = get_ccall;
/* cast pointer to actual type if appropriate */
if (stmt.type_reference.data_type is Struct) {
var st = (Struct) stmt.type_reference.data_type;
if (st == uint_type.data_type) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
cconv.add_argument (element_expr);
element_expr = cconv;
} else if (st == bool_type.data_type || st.is_integer_type ()) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
cconv.add_argument (element_expr);
element_expr = cconv;
}
}
element_expr = convert_from_generic_pointer (element_expr, stmt.type_reference);
var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
......@@ -1941,10 +1921,12 @@ public class Vala.CodeGenerator : CodeVisitor {
{
List<weak Expression> indices = expr.get_indices ();
int rank = indices.length ();
var container_type = expr.container.static_type.data_type;
var ccontainer = (CCodeExpression) expr.container.ccodenode;
var cindex = (CCodeExpression) indices.nth_data (0).ccodenode;
if (expr.container.static_type.data_type == string_type.data_type) {
if (container_type == string_type.data_type) {
// access to unichar in a string
var coffsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_utf8_offset_to_pointer"));
coffsetcall.add_argument (ccontainer);
......@@ -1954,6 +1936,23 @@ public class Vala.CodeGenerator : CodeVisitor {
ccall.add_argument (coffsetcall);
expr.ccodenode = ccall;
} else if (container_type != null && list_type != null && map_type != null &&
(container_type == list_type || container_type.is_subtype_of (list_type) ||
container_type == map_type || container_type.is_subtype_of (map_type))) {
var get_method = (Method) container_type.scope.lookup ("get");
List<weak FormalParameter> get_params = get_method.get_parameters ();
var get_param = (FormalParameter) get_params.data;
if (get_param.type_reference.type_parameter != null) {
var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, get_method, get_param.type_reference.type_parameter, expr);
cindex = convert_to_generic_pointer (cindex, index_type);
}
var get_ccall = new CCodeFunctionCall (new CCodeIdentifier (get_method.get_cname ()));
get_ccall.add_argument (new CCodeCastExpression (ccontainer, container_type.get_cname () + "*"));
get_ccall.add_argument (cindex);
expr.ccodenode = convert_from_generic_pointer (get_ccall, expr.static_type);
} else {
// access to element in an array
for (int i = 1; i < rank; i++) {
......@@ -2057,7 +2056,7 @@ public class Vala.CodeGenerator : CodeVisitor {
var ccomma = new CCodeCommaExpression ();
ccomma.append_expression (new CCodeAssignment (ctemp, (CCodeExpression) expr.ccodenode));
if (expr.static_type.data_type == list_type) {
if (expr.static_type.data_type == glist_type) {
bool is_ref = false;
bool is_class = false;
bool is_interface = false;
......@@ -2127,8 +2126,8 @@ public class Vala.CodeGenerator : CodeVisitor {
ccall.add_argument (new CCodeConstant ("NULL"));
expr.ccodenode = ccall;
} else if (expr.type_reference.data_type == list_type ||
expr.type_reference.data_type == slist_type) {
} else if (expr.type_reference.data_type == glist_type ||
expr.type_reference.data_type == gslist_type) {
// NULL is an empty list
expr.ccodenode = new CCodeConstant ("NULL");
} else {
......@@ -2391,4 +2390,38 @@ public class Vala.CodeGenerator : CodeVisitor {
public override void visit_end_lambda_expression (LambdaExpression! l) {
l.ccodenode = new CCodeIdentifier (l.method.get_cname ());
}
private CCodeExpression! convert_from_generic_pointer (CCodeExpression! cexpr, TypeReference! actual_type) {
var result = cexpr;
if (actual_type.data_type is Struct) {
var st = (Struct) actual_type.data_type;
if (st == uint_type.data_type) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
cconv.add_argument (cexpr);
result = cconv;
} else if (st == bool_type.data_type || st.is_integer_type ()) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
cconv.add_argument (cexpr);
result = cconv;
}
}
return result;
}
private CCodeExpression! convert_to_generic_pointer (CCodeExpression! cexpr, TypeReference! actual_type) {
var result = cexpr;
if (actual_type.data_type is Struct) {
var st = (Struct) actual_type.data_type;
if (st == uint_type.data_type) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GUINT_TO_POINTER"));
cconv.add_argument (cexpr);
result = cconv;
} else if (st == bool_type.data_type || st.is_integer_type ()) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER"));
cconv.add_argument (cexpr);
result = cconv;
}
}
return result;
}
}
......@@ -191,6 +191,48 @@ public class Vala.CodeGenerator {
}
a.ccodenode = ccall;
} else if (a.left is ElementAccess && !(((ElementAccess) a.left).container.static_type.data_type is Array)) {
// custom element access
CCodeExpression rhs = (CCodeExpression) a.right.ccodenode;
if (a.left.static_type.data_type != null
&& a.right.static_type.data_type != null
&& a.left.static_type.data_type.is_reference_type ()
&& a.right.static_type.data_type != a.left.static_type.data_type) {
var ccast = new CCodeFunctionCall (new CCodeIdentifier (a.left.static_type.data_type.get_upper_case_cname (null)));
ccast.add_argument (rhs);
rhs = ccast;
}
var expr = (ElementAccess) a.left;
var container_type = expr.container.static_type.data_type;
List<weak Expression> indices = expr.get_indices ();
var ccontainer = (CCodeExpression) expr.container.ccodenode;
var cindex = (CCodeExpression) indices.nth_data (0).ccodenode;
if (container_type != null && list_type != null && map_type != null &&
(container_type == list_type || container_type.is_subtype_of (list_type) ||
container_type == map_type || container_type.is_subtype_of (map_type))) {
var set_method = (Method) container_type.scope.lookup ("set");
List<weak FormalParameter> set_params = set_method.get_parameters ();
var set_param = (FormalParameter) set_params.data;
if (set_param.type_reference.type_parameter != null) {
var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, set_method, set_param.type_reference.type_parameter, a);
cindex = convert_to_generic_pointer (cindex, index_type);
}
var set_ccall = new CCodeFunctionCall (new CCodeIdentifier (set_method.get_cname ()));
set_ccall.add_argument (new CCodeCastExpression (ccontainer, container_type.get_cname () + "*"));
set_ccall.add_argument (cindex);
set_ccall.add_argument (convert_to_generic_pointer (rhs, expr.static_type));
a.ccodenode = set_ccall;
} else {
Report.error (a.source_reference, "internal error: unsupported element access");
a.error = true;
}
} else {
CCodeExpression rhs = (CCodeExpression) a.right.ccodenode;
......
......@@ -126,13 +126,7 @@ public class Vala.CodeGenerator {
cexpr = new CCodeCastExpression (cexpr, param.type_reference.data_type.get_cname ());
} else if (param.type_reference.data_type == null
&& arg.static_type.data_type is Struct) {
/* convert integer to pointer if this is a generic method parameter */
var st = (Struct) arg.static_type.data_type;
if (st == bool_type.data_type || st.is_integer_type ()) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER"));
cconv.add_argument (cexpr);
cexpr = cconv;
}
cexpr = convert_to_generic_pointer (cexpr, arg.static_type);
}
}
}
......@@ -216,21 +210,10 @@ public class Vala.CodeGenerator {
} else {
/* cast pointer to actual type if this is a generic method return value */
if (m != null && m.return_type.type_parameter != null && expr.static_type.data_type != null) {
if (expr.static_type.data_type is Struct) {
var st = (Struct) expr.static_type.data_type;
if (st == uint_type.data_type) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
cconv.add_argument (ccall);
ccall = cconv;
} else if (st == bool_type.data_type || st.is_integer_type ()) {
var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
cconv.add_argument (ccall);
ccall = cconv;
}
}
expr.ccodenode = convert_from_generic_pointer (ccall, expr.static_type);
} else {
expr.ccodenode = ccall;
}
expr.ccodenode = ccall;
visit_expression (expr);
}
......
......@@ -186,7 +186,7 @@ public class Vala.MemoryManager : CodeVisitor {
if (is_ref && param.type_reference.type_parameter != null) {
if (expr.call is MemberAccess) {
var ma = (MemberAccess) expr.call;
var param_type = get_actual_type (ma.inner.static_type, msym, param.type_reference.type_parameter, expr);
var param_type = SemanticAnalyzer.get_actual_type (ma.inner.static_type, msym, param.type_reference.type_parameter, expr);
if (param_type != null) {
is_ref = param_type.takes_ownership;
}
......@@ -227,7 +227,7 @@ 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) {
var param_type = get_actual_type (expr.type_reference, msym, param.type_reference.type_parameter, expr);
var param_type = SemanticAnalyzer.get_actual_type (expr.type_reference, msym, param.type_reference.type_parameter, expr);
if (param_type != null) {
is_ref = param_type.takes_ownership;
}
......@@ -249,64 +249,6 @@ public class Vala.MemoryManager : CodeVisitor {
}
}
private TypeReference get_actual_type (TypeReference instance_type, Symbol generic_member, TypeParameter type_parameter, CodeNode node_reference) {
// trace type arguments back to the datatype where the method has been declared
// TODO move this to semantic analyzer
while (instance_type.data_type != generic_member.parent_symbol) {
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 (node_reference.source_reference, "internal error: unsupported generic type");
node_reference.error = true;
return null;
}
foreach (TypeReference base_type in base_types) {
if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, generic_member.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 (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
node_reference.error = true;
return null;
}
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 != generic_member.parent_symbol) {
Report.error (node_reference.source_reference, "internal error: generic type parameter tracing not supported yet");
node_reference.error = true;
return null;
}
int param_index = instance_type.data_type.get_type_parameter_index (type_parameter.name);
if (param_index == -1) {
Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_parameter.name));
node_reference.error = true;
return null;
}
var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
if (param_type == null) {
Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (type_parameter.name));
node_reference.error = true;
return null;
}
return param_type;
}
public override void visit_binary_expression (BinaryExpression! expr) {
visit_possibly_leaked_expression (expr.left);
visit_possibly_leaked_expression (expr.right);
......
......@@ -55,6 +55,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
DataType gslist_type;
DataType gerror_type;
DataType iterable_type;
DataType list_type;
DataType map_type;
private int next_lambda_id = 0;
......@@ -108,6 +110,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
var gee_ns = root_symbol.scope.lookup ("Gee");
if (gee_ns != null) {
iterable_type = (DataType) gee_ns.scope.lookup ("Iterable");
list_type = (DataType) gee_ns.scope.lookup ("List");
map_type = (DataType) gee_ns.scope.lookup ("Map");
}
current_symbol = root_symbol;
......@@ -1434,58 +1438,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
expr.error = true;
return;
} else {
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) {
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, 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) {
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);
ret_type = get_actual_type (ma.inner.static_type, msym, ret_type.type_parameter, expr);
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;
}
}
......@@ -1502,6 +1456,63 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
check_arguments (expr, msym, params, expr.get_argument_list ());
}
public static TypeReference get_actual_type (TypeReference instance_type, Symbol generic_member, TypeParameter type_parameter, CodeNode node_reference) {
// trace type arguments back to the datatype where the method has been declared
while (instance_type.data_type != generic_member.parent_symbol) {
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 (node_reference.source_reference, "internal error: unsupported generic type");
node_reference.error = true;
return null;
}
foreach (TypeReference base_type in base_types) {
if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, generic_member.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 (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
node_reference.error = true;
return null;
}
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 != generic_member.parent_symbol) {
Report.error (node_reference.source_reference, "internal error: generic type parameter tracing not supported yet");
node_reference.error = true;
return null;
}
int param_index = instance_type.data_type.get_type_parameter_index (type_parameter.name);
if (param_index == -1) {
Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_parameter.name));
node_reference.error = true;
return null;
}
var actual_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
if (actual_type == null) {
Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (type_parameter.name));
node_reference.error = true;
return null;
}
return actual_type;
}
public override void visit_element_access (ElementAccess! expr) {
if (expr.container.static_type == null) {
/* don't proceed if a child expression failed */
......@@ -1509,8 +1520,12 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
return;
}
var container_type = expr.container.static_type.data_type;
bool index_int_type_check = true;
/* assign a static_type when possible */
if (expr.container.static_type.data_type is Array) {
if (container_type is Array) {
var args = expr.container.static_type.get_type_arguments ();
if (args.length () != 1) {
......@@ -1520,7 +1535,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
expr.static_type = (TypeReference) args.data;
} else if (expr.container.static_type.data_type == string_type.data_type) {
} else if (container_type == string_type.data_type) {
if (expr.get_indices ().length () != 1) {
expr.error = true;
Report.error (expr.source_reference, "Element access with more than one dimension is not supported for strings");
......@@ -1528,22 +1543,59 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
expr.static_type = unichar_type;
} else if (container_type != null && list_type != null && map_type != null &&
(container_type == list_type || container_type.is_subtype_of (list_type) ||
container_type == map_type || container_type.is_subtype_of (map_type))) {
List<weak Expression> indices = expr.get_indices ();
if (indices.length () != 1) {
expr.error = true;
Report.error (expr.source_reference, "Element access with more than one dimension is not supported for the specified type");
return;
}
var index = (Expression) indices.data;
index_int_type_check = false;
var get_sym = container_type.scope.lookup ("get");
if (!(get_sym is Method)) {
expr.error = true;
Report.error (expr.source_reference, "invalid get method in specified collection type");
return;
}
var get_method = (Method) get_sym;
List<weak FormalParameter> get_params = get_method.get_parameters ();
var get_param = (FormalParameter) get_params.data;
var index_type = get_param.type_reference;
if (index_type.type_parameter != null) {
index_type = get_actual_type (expr.container.static_type, get_method, get_param.type_reference.type_parameter, expr);
}
if (!is_type_compatible (index.static_type, index_type)) {
expr.error = true;
Report.error (expr.source_reference, "index expression: Cannot convert from `%s' to `%s'".printf (index.static_type.to_string (), index_type.to_string ()));
return;
}
expr.static_type = get_actual_type (expr.container.static_type, get_method, get_method.return_type.type_parameter, expr).copy ();
expr.static_type.takes_ownership = false;
} else {
expr.error = true;
Report.error (expr.source_reference, "The expression `%s' does not denote an Array".printf (expr.container.static_type.to_string ()));
}
/* check if the index is of type integer */
foreach (Expression e in expr.get_indices ()) {
/* don't proceed if a child expression failed */
if (e.static_type == null) {
return;
}
if (index_int_type_check) {
/* check if the index is of type integer */
if (!(e.static_type.data_type is Struct) || !((Struct) e.static_type.data_type).is_integer_type ()) {
expr.error = true;
Report.error (e.source_reference, "Expression of integer type expected");
<