@@ -33,8 +33,10 @@ pointer_typet select_pointer_typet::convert_pointer_type(
33
33
if (!generic_parameter_specialization_map.empty ())
34
34
{
35
35
generic_parameter_recursion_trackingt visited;
36
- return specialize_generics (
36
+ auto type = specialize_generics (
37
37
pointer_type, generic_parameter_specialization_map, visited);
38
+ INVARIANT (visited.empty (), " recursion stack must be empty here" );
39
+ return type;
38
40
}
39
41
else
40
42
{
@@ -86,18 +88,31 @@ pointer_typet select_pointer_typet::specialize_generics(
86
88
// information from further recursion, only cause a segmentation fault.
87
89
if (visited_nodes.find (parameter_name) != visited_nodes.end ())
88
90
{
91
+ optionalt<pointer_typet> result = get_instantiated_type (
92
+ parameter_name, generic_parameter_specialization_map);
93
+ if (result.has_value ())
94
+ {
95
+ return result.value ();
96
+ }
89
97
throw " no infinite recursion" ;
90
98
}
91
99
92
- visited_nodes.insert (parameter_name);
93
-
94
100
// generic parameters can be adopted from outer classes or superclasses so
95
101
// we may need to search for the concrete type recursively
96
- return is_java_generic_parameter (type)
97
- ? specialize_generics (
98
- to_java_generic_parameter (type),
99
- generic_parameter_specialization_map, visited_nodes)
100
- : type;
102
+ if (is_java_generic_parameter (type))
103
+ {
104
+ visited_nodes.insert (parameter_name);
105
+ auto returned_type = specialize_generics (
106
+ to_java_generic_parameter (type),
107
+ generic_parameter_specialization_map,
108
+ visited_nodes);
109
+ visited_nodes.erase (parameter_name);
110
+ return returned_type;
111
+ }
112
+ else
113
+ {
114
+ return type;
115
+ }
101
116
}
102
117
else if (pointer_type.subtype ().id () == ID_symbol)
103
118
{
@@ -120,3 +135,88 @@ pointer_typet select_pointer_typet::specialize_generics(
120
135
}
121
136
return pointer_type;
122
137
}
138
+
139
+ // / Return the first concrete type instantiation if any such exists.
140
+ // / \param parameter_name The name of the generic parameter type we want to have
141
+ // / instantiated
142
+ // / \param generic_specialization_map Map of type names to specialization stack
143
+ // / \param depth start depth for instantiation search
144
+ // / \return the first instantiated type for the generic type or nothing if no
145
+ // / such instantiation exists.
146
+ optionalt<pointer_typet> select_pointer_typet::get_instantiated_type (
147
+ const irep_idt ¶meter_name,
148
+ const generic_parameter_specialization_mapt
149
+ &generic_parameter_specialization_map) const
150
+ {
151
+ generic_parameter_recursion_trackingt visited;
152
+ const auto retval = get_instantiated_type (
153
+ parameter_name, generic_parameter_specialization_map, visited, 0 );
154
+ INVARIANT (visited.empty (), " recursion set must be empty here" );
155
+ return retval;
156
+ }
157
+
158
+ // / See above, the additional parameter just tracks the recursion to prevent
159
+ // / visiting the same depth again.
160
+ // / \param visited tracks the visited parameter names
161
+ optionalt<pointer_typet> select_pointer_typet::get_instantiated_type (
162
+ const irep_idt ¶meter_name,
163
+ const generic_parameter_specialization_mapt
164
+ &generic_parameter_specialization_map,
165
+ generic_parameter_recursion_trackingt &visited,
166
+ const size_t depth) const
167
+ {
168
+ // Get the pointed to instantiation type at the desired stack depth.
169
+ // - f this type is not a generic type, it is returned as a valid
170
+ // instantiation
171
+ // - if another recursion at this depth level is found, the search depth is
172
+ // increased
173
+ // - if nothing can be found an empty optional is returned
174
+
175
+ if (
176
+ generic_parameter_specialization_map.find (parameter_name) !=
177
+ generic_parameter_specialization_map.end ())
178
+ {
179
+ const auto &replacements =
180
+ generic_parameter_specialization_map.find (parameter_name)->second ;
181
+
182
+ // max depth reached and nothing found
183
+ if (replacements.size () <= depth)
184
+ return {};
185
+
186
+ // Check if there is a recursion loop, if yes increase search depth
187
+ if (visited.find (parameter_name) != visited.end ())
188
+ {
189
+ visited.clear ();
190
+ return get_instantiated_type (
191
+ parameter_name, generic_parameter_specialization_map, visited, depth+1 );
192
+ }
193
+ else
194
+ {
195
+ const size_t index = (replacements.size () - depth) - 1 ;
196
+ const auto &type = replacements[index ];
197
+ {
198
+ if (!is_java_generic_parameter (type))
199
+ {
200
+ return type;
201
+ }
202
+ else
203
+ {
204
+ visited.insert (parameter_name);
205
+ const auto &gen_type = to_java_generic_parameter (type).type_variable ();
206
+ const auto val = get_instantiated_type (
207
+ gen_type.get_identifier (),
208
+ generic_parameter_specialization_map,
209
+ visited,
210
+ depth);
211
+ visited.erase (parameter_name);
212
+ return val;
213
+ }
214
+ }
215
+ }
216
+ }
217
+ // parameter_name not found in map
218
+ else
219
+ {
220
+ UNREACHABLE;
221
+ }
222
+ }
0 commit comments