Skip to content

Commit 3d37cb5

Browse files
author
thk123
committed
Extend the specialisation code to handle generic fields
Previously we didn't handle generic fields when we were doing specialisation, meaning they were missed. This resolves this and adds a unit test to demonstrate it.
1 parent b0c4cfa commit 3d37cb5

File tree

3 files changed

+69
-15
lines changed

3 files changed

+69
-15
lines changed

src/java_bytecode/generate_java_generic_type.cpp

+53-14
Original file line numberDiff line numberDiff line change
@@ -118,22 +118,61 @@ typet generate_java_generic_typet::substitute_type(
118118
}
119119
}
120120
else if(
121-
parameter_type.id() == ID_pointer &&
122-
parameter_type.subtype().id() == ID_symbol)
121+
parameter_type.id() == ID_pointer)
123122
{
124-
const symbol_typet &array_subtype =
125-
to_symbol_type(parameter_type.subtype());
126-
if(is_java_array_tag(array_subtype.get_identifier()))
123+
if(is_java_generic_type(parameter_type))
127124
{
128-
const typet &array_element_type = java_array_element_type(array_subtype);
129-
130-
const typet &new_array_type =
131-
substitute_type(array_element_type, generic_class, generic_reference);
132-
133-
typet replacement_array_type = java_array_type('a');
134-
replacement_array_type.subtype().set(
135-
ID_C_element_type, new_array_type);
136-
return replacement_array_type;
125+
const java_generic_typet &generic_type =
126+
to_java_generic_type(parameter_type);
127+
128+
java_generic_typet::generic_type_variablest replaced_type_variables;
129+
130+
// Swap each parameter
131+
std::transform(
132+
generic_type.generic_type_variables().begin(),
133+
generic_type.generic_type_variables().end(),
134+
std::back_inserter(replaced_type_variables),
135+
[&](const java_generic_parametert &generic_param)
136+
-> java_generic_parametert {
137+
const typet &replacement_type =
138+
substitute_type(generic_param, generic_class, generic_reference);
139+
140+
// This code will be simplified when references aren't considered to
141+
// be generic parameters
142+
if(is_java_generic_parameter(replacement_type))
143+
{
144+
return to_java_generic_parameter(replacement_type);
145+
}
146+
else
147+
{
148+
INVARIANT(
149+
is_reference(replacement_type),
150+
"All generic parameters should be references");
151+
return java_generic_inst_parametert(
152+
to_symbol_type(replacement_type.subtype()));
153+
}
154+
});
155+
156+
java_generic_typet new_type=generic_type;
157+
new_type.generic_type_variables()=replaced_type_variables;
158+
return new_type;
159+
}
160+
else if(parameter_type.subtype().id() == ID_symbol)
161+
{
162+
const symbol_typet &array_subtype =
163+
to_symbol_type(parameter_type.subtype());
164+
if(is_java_array_tag(array_subtype.get_identifier()))
165+
{
166+
const typet &array_element_type = java_array_element_type(array_subtype);
167+
168+
const typet &new_array_type =
169+
substitute_type(array_element_type, generic_class, generic_reference);
170+
171+
typet replacement_array_type = java_array_type('a');
172+
replacement_array_type.subtype().set(
173+
ID_C_element_type, new_array_type);
174+
return replacement_array_type;
175+
}
137176
}
138177
}
139178
return parameter_type;

unit/java_bytecode/generate_concrete_generic_type/generate_java_generic_type.cpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,9 @@ SCENARIO("generate_java_generic_type with a generic array field")
260260
const symbolt test_class_symbol =
261261
new_symbol_table.lookup_ref(specialised_class_name);
262262

263+
REQUIRE(test_class_symbol.type.id() == ID_struct);
263264
THEN("The array field should be specialised to be an array of floats")
264265
{
265-
REQUIRE(test_class_symbol.type.id() == ID_struct);
266266
const struct_typet::componentt &field_component =
267267
require_type::require_component(
268268
to_struct_type(test_class_symbol.type), "arrayField");
@@ -278,6 +278,19 @@ SCENARIO("generate_java_generic_type with a generic array field")
278278
require_type::require_pointer(
279279
array_type, symbol_typet("java::java.lang.Float"));
280280
}
281+
282+
THEN("The generic class field should be specialised to be a generic "
283+
"class with the appropriate type")
284+
{
285+
const struct_typet::componentt &field_component =
286+
require_type::require_component(
287+
to_struct_type(test_class_symbol.type), "genericClassField");
288+
289+
require_type::require_java_generic_type(
290+
field_component.type(),
291+
{{require_type::type_parameter_kindt::Inst,"java::java.lang.Float"}});
292+
}
293+
281294
}
282295
}
283296
}

unit/java_bytecode/generate_concrete_generic_type/generic_field_array_instantiation.java

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ class generic<T> {
66

77
class genericArray<T> {
88
T [] arrayField;
9+
10+
generic<T> genericClassField;
911
}
1012

1113
generic<Float []> f;

0 commit comments

Comments
 (0)