-
Notifications
You must be signed in to change notification settings - Fork 274
[TG-7815] Fix bug in get_recursively_instantiated_type #4913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
4abbd7a
cf6d6fb
e4b7363
8125a9f
ec69b1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,61 +25,60 @@ pointer_typet select_pointer_typet::convert_pointer_type( | |
// a generic parameter, specialize it with concrete types | ||
if(!generic_parameter_specialization_map.empty()) | ||
{ | ||
generic_parameter_recursion_trackingt visited; | ||
const auto &type = specialize_generics( | ||
pointer_type, generic_parameter_specialization_map, visited); | ||
INVARIANT(visited.empty(), "recursion stack must be empty here"); | ||
return type; | ||
return specialize_generics( | ||
pointer_type, generic_parameter_specialization_map); | ||
} | ||
else | ||
{ | ||
return pointer_type; | ||
} | ||
} | ||
|
||
/// Return the first concrete type instantiation if any such exists. | ||
/// | ||
/// Example: | ||
/// `class MyGeneric<T,U> { MyGeneric<U,T> gen; T t;}` | ||
/// When instantiating `MyGeneric<Integer,String> my` we need to for example | ||
/// resolve the type of `my.gen.t`. The map would in this context contain | ||
/// - T -> (Integer, U) | ||
/// - U -> (String, T) | ||
/// | ||
/// Note that the top of the stacks for T and U create a recursion T -> U, | ||
/// U-> T. We want to break it and specialize `T my.gen.t` to `String my.gen.t`. | ||
/// \param pointer_type: The pointer type to specialize | ||
/// \param generic_parameter_specialization_map: Map of type names to | ||
/// specialization stack | ||
/// \return The first instantiated type for the generic type or nothing if no | ||
/// such instantiation exists. | ||
pointer_typet select_pointer_typet::specialize_generics( | ||
const pointer_typet &pointer_type, | ||
const generic_parameter_specialization_mapt | ||
&generic_parameter_specialization_map, | ||
generic_parameter_recursion_trackingt &visited_nodes) const | ||
&generic_parameter_specialization_map) const | ||
{ | ||
auto parameter = type_try_dynamic_cast<java_generic_parametert>(pointer_type); | ||
if(parameter != nullptr) | ||
{ | ||
const irep_idt ¶meter_name = parameter->get_name(); | ||
irep_idt parameter_name = parameter->get_name(); | ||
|
||
// avoid infinite recursion by looking at each generic argument from | ||
// previous assignments | ||
if(visited_nodes.find(parameter_name) != visited_nodes.end()) | ||
generic_parameter_specialization_mapt spec_map_copy = | ||
generic_parameter_specialization_map; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 You're making a copy of the map over and over again, changing a single element in it in each call. I don't have any good idea how to make this less costly though.. not so nice ideas being keeping two functions, make the code uglier at the call site, or add extra arguments to the function (depth of each stack to look at). Can you think of a better way? |
||
while(true) | ||
{ | ||
const optionalt<pointer_typet> result = get_recursively_instantiated_type( | ||
parameter_name, generic_parameter_specialization_map); | ||
return result.has_value() ? result.value() : pointer_type; | ||
auto types_it = spec_map_copy.find(parameter_name); | ||
if(types_it == spec_map_copy.end() || types_it->second.empty()) | ||
{ | ||
// This means that the generic pointer_type has not been specialized | ||
// in the current context (e.g., the method under test is generic); | ||
// we return the pointer_type itself which is a pointer to its upper | ||
// bound | ||
return pointer_type; | ||
} | ||
const reference_typet &type = types_it->second.back(); | ||
types_it->second.pop_back(); | ||
if(!is_java_generic_parameter(type)) | ||
return type; | ||
parameter_name = to_java_generic_parameter(type).get_name(); | ||
} | ||
|
||
if(generic_parameter_specialization_map.count(parameter_name) == 0) | ||
{ | ||
// this means that the generic pointer_type has not been specialized | ||
// in the current context (e.g., the method under test is generic); | ||
// we return the pointer_type itself which is basically a pointer to | ||
// its upper bound | ||
return pointer_type; | ||
} | ||
const pointer_typet &type = | ||
generic_parameter_specialization_map.find(parameter_name)->second.back(); | ||
|
||
// generic parameters can be adopted from outer classes or superclasses so | ||
// we may need to search for the concrete type recursively | ||
if(!is_java_generic_parameter(type)) | ||
return type; | ||
|
||
visited_nodes.insert(parameter_name); | ||
const auto returned_type = specialize_generics( | ||
to_java_generic_parameter(type), | ||
generic_parameter_specialization_map, | ||
visited_nodes); | ||
visited_nodes.erase(parameter_name); | ||
return returned_type; | ||
} | ||
|
||
auto subtype = | ||
|
@@ -94,8 +93,7 @@ pointer_typet select_pointer_typet::specialize_generics( | |
|
||
const pointer_typet &new_array_type = specialize_generics( | ||
*array_element_type, | ||
generic_parameter_specialization_map, | ||
visited_nodes); | ||
generic_parameter_specialization_map); | ||
|
||
pointer_typet replacement_array_type = java_array_type('a'); | ||
replacement_array_type.subtype().set(ID_element_type, new_array_type); | ||
|
@@ -105,47 +103,6 @@ pointer_typet select_pointer_typet::specialize_generics( | |
return pointer_type; | ||
} | ||
|
||
/// Return the first concrete type instantiation if any such exists. This method | ||
/// is only to be called when \ref select_pointer_typet::specialize_generics | ||
/// cannot find an instantiation due to a loop in its recursion. | ||
/// | ||
/// Example: | ||
/// `class MyGeneric<T,U> { MyGeneric<U,T> gen; T t;}` | ||
/// When instantiating `MyGeneric<Integer,String> my` we need to for example | ||
/// resolve the type of `my.gen.t`. The map would in this context contain | ||
/// - T -> (Integer, U) | ||
/// - U -> (String, T) | ||
/// | ||
/// Note that the top of the stacks for T and U create a recursion T -> U, | ||
/// U-> T. We want to break it and specialize `T my.gen.t` to `String my.gen.t`. | ||
/// \param parameter_name: The name of the generic parameter type we want to | ||
/// have instantiated | ||
/// \param generic_parameter_specialization_map: Map of type names to | ||
/// specialization stack | ||
/// \return The first instantiated type for the generic type or nothing if no | ||
/// such instantiation exists. | ||
optionalt<pointer_typet> | ||
select_pointer_typet::get_recursively_instantiated_type( | ||
irep_idt parameter_name, | ||
generic_parameter_specialization_mapt | ||
generic_parameter_specialization_map) const | ||
{ | ||
while(true) | ||
{ | ||
auto types_it = generic_parameter_specialization_map.find(parameter_name); | ||
INVARIANT( | ||
types_it != generic_parameter_specialization_map.end(), | ||
"Type parameter must have a type argument"); | ||
if(types_it->second.empty()) | ||
return {}; | ||
reference_typet type = types_it->second.back(); | ||
types_it->second.pop_back(); | ||
if(!is_java_generic_parameter(type)) | ||
return std::move(type); | ||
parameter_name = to_java_generic_parameter(type).get_name(); | ||
} | ||
} | ||
|
||
std::set<struct_tag_typet> | ||
select_pointer_typet::get_parameter_alternative_types( | ||
const irep_idt &, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be updated slightly - it sounds l like it's only handling the recursion case (because it's just moved from the function that was breaking recursion). Also, move the documentation to the header.