-
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
[TG-7815] Fix bug in get_recursively_instantiated_type #4913
Conversation
When there is recursion we ended up duplicating effort and the recursion-handling method is now more simple anyway. Also avoids essentially duplicated code.
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.
Also please add at least one regression test exposing the bug (or better yet, KNOWNBUG -> CORE an existing test), and there seem to be real unit test failures in CI.
if(!is_java_generic_parameter(type)) | ||
{ | ||
return type; | ||
auto types_it = generic_parameter_specialization_map.find(parameter_name); |
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.
Commit message: note what the bug was and how this fixes it
|
||
irep_idt current_parameter = parameter_name; | ||
for(size_t depth = 0; depth < max_depth; depth++) | ||
while(true) |
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.
Looks good, but since taking a map by value like this is quite unusual please add comments noting the strategy you're using here and why
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.
The map itself is not taken by value. I don't think we need to document why passing a struct by value is OK.
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.
I'm not sure what you mean by "not taken by value". We do make a copy here, so we can pop from the stacks of particular parameters in the map just for the sake of finding the parameter specialization, but at the call site of this function we need to keep the original full information. I agree that adding a note that points this out is useful (not arguing why it's ok, just to make the reader notice), I missed it myself at first.
return replacement_array_type; | ||
} | ||
} | ||
auto array_element_type = |
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.
const auto *
for clarity?
} | ||
|
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.
Don't re-space in the same commit as a substantial change
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.
Should be fine once the tests are in.
|
||
irep_idt current_parameter = parameter_name; | ||
for(size_t depth = 0; depth < max_depth; depth++) | ||
while(true) |
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.
The map itself is not taken by value. I don't think we need to document why passing a struct by value is OK.
/// Checks whether the type is a java generic parameter/variable, e.g., `T` in | ||
/// `List<T>`. | ||
/// \param type: the type to check | ||
/// \return true if type is a generic Java parameter type | ||
inline bool is_java_generic_parameter(const typet &type) | ||
{ | ||
return is_reference(type) && is_java_generic_parameter_tag(type.subtype()); | ||
return can_cast_type<java_generic_parametert>(type); |
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.
Should probably be in a separate commit. It does not correspond to the commit description. There are several things being changed here, and it makes it difficult to check that this commit does not introduce a behavioural change.
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.
Needs some cleanup but I love it 🙂
|
||
template <typename ostream> | ||
ostream & | ||
operator<<(ostream &stm, const print_generic_parameter_specialization_map &map) |
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 is useful
|
||
irep_idt current_parameter = parameter_name; | ||
for(size_t depth = 0; depth < max_depth; depth++) | ||
while(true) |
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.
I'm not sure what you mean by "not taken by value". We do make a copy here, so we can pop from the stacks of particular parameters in the map just for the sake of finding the parameter specialization, but at the call site of this function we need to keep the original full information. I agree that adding a note that points this out is useful (not arguing why it's ok, just to make the reader notice), I missed it myself at first.
/// \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. |
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.
// 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 comment
The 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?
This solution was inadequate. Replacing with a new solution. |
This reduces the amount of code and in so doing fixes the implementation of specialization of generics.
Previously the following invariant was being triggered in non-symmetric mutual generic specialization: