@@ -33,8 +33,10 @@ pointer_typet select_pointer_typet::convert_pointer_type(
3333 if (!generic_parameter_specialization_map.empty ())
3434 {
3535 generic_parameter_recursion_trackingt visited;
36- return specialize_generics (
36+ auto type = specialize_generics (
3737 pointer_type, generic_parameter_specialization_map, visited);
38+ INVARIANT (visited.empty (), " recursion stack must be empty here" );
39+ return type;
3840 }
3941 else
4042 {
@@ -86,18 +88,31 @@ pointer_typet select_pointer_typet::specialize_generics(
8688 // information from further recursion, only cause a segmentation fault.
8789 if (visited_nodes.find (parameter_name) != visited_nodes.end ())
8890 {
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+ }
8997 throw " no infinite recursion" ;
9098 }
9199
92- visited_nodes.insert (parameter_name);
93-
94100 // generic parameters can be adopted from outer classes or superclasses so
95101 // 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+ }
101116 }
102117 else if (pointer_type.subtype ().id () == ID_symbol)
103118 {
@@ -120,3 +135,88 @@ pointer_typet select_pointer_typet::specialize_generics(
120135 }
121136 return pointer_type;
122137}
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