-
Notifications
You must be signed in to change notification settings - Fork 274
Fix generic_parameter_specialization_map in the presence of non-symmetric generic recursion [TG-7815] #4929
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
Fix generic_parameter_specialization_map in the presence of non-symmetric generic recursion [TG-7815] #4929
Conversation
d1c2855
to
7c01b9a
Compare
} | ||
const auto *array_element_type = | ||
type_try_dynamic_cast<pointer_typet>(java_array_element_type(*subtype)); | ||
if(array_element_type == nullptr) |
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 commit ("Use type_try_dynamic_cast") does more than its message says (it also switches from if(x) y
to if(!x) return; y;
style)
@@ -5,6 +5,7 @@ SRC = assignments_from_json.cpp \ | |||
ci_lazy_methods_needed.cpp \ | |||
convert_java_nondet.cpp \ | |||
expr2java.cpp \ | |||
generic_parameter_specialization_map.cpp \ |
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 for "Change data storage for generic_parameter_specialization_mapt" has got a bit out of hand -- the "Added ability to output..." bit probably doesn't need to be there if we're adding it at the same time as the map itself, and similarly "Add test..."
map.map.container_to_specializations.size()); | ||
for(const auto &elt : map.map.param_to_container) | ||
{ | ||
std::vector<irep_idt> ¶ms = container_to_params[elt.second.first]; |
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.
Using structs instead of pair
would make it easier to understand what you're referring to here
@@ -151,17 +123,18 @@ void generic_parameter_specialization_map_keyst::insert_pairs_for_symbol( | |||
{ | |||
return; | |||
} | |||
|
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.
Spacing fixups should be in their own commit
{ | ||
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(); |
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.
No need for this to change? const irep_idt &
is pretty widely used for a const irept
's data, this probably isn't the place to fight that battle
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 assign to it at the bottom of the loop.
@@ -23,12 +23,10 @@ class generic_parameter_specialization_map_keyst | |||
public: | |||
/// Initialize a generic-parameter-specialization-map entry owner operating | |||
/// on a given map. Initially it does not own any map entry. | |||
/// \param _generic_parameter_specialization_map: map to operate on. | |||
/// \param generic_parameter_specialization_map: map to operate on. |
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.
Probably split commit "Code cleanup", e.g. "factor out get_final_name_component", one commit per variable rename, the stuff with new_class_type
, the re-spacing are all pretty independent changes.
@@ -1200,6 +1200,17 @@ void mark_java_implicitly_generic_class_type( | |||
java_implicitly_generic_class_typet new_class_type( | |||
class_type, implicit_generic_type_parameters); | |||
|
|||
// Prepend existing parameters so choose those above any inherited |
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 commit should include a test
833e1b7
to
fcda9ce
Compare
Codecov Report
@@ Coverage Diff @@
## develop #4929 +/- ##
===========================================
+ Coverage 69.29% 69.31% +0.01%
===========================================
Files 1306 1308 +2
Lines 108263 108314 +51
===========================================
+ Hits 75023 75074 +51
Misses 33240 33240
Continue to review full report at Codecov.
|
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 PR failed Diffblue compatibility checks (cbmc commit: 833e1b7).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/120497981
Status will be re-evaluated on next push.
Common spurious failures include: the cbmc commit has disappeared in the mean time (e.g. in a force-push); the author is not in the list of contributors (e.g. first-time contributors); compatibility was already broken by an earlier merge.
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 PR failed Diffblue compatibility checks (cbmc commit: fcda9ce).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/120498877
Status will be re-evaluated on next push.
Common spurious failures include: the cbmc commit has disappeared in the mean time (e.g. in a force-push); the author is not in the list of contributors (e.g. first-time contributors); compatibility was already broken by an earlier merge.
param_it->second.container_index == container_index, | ||
"Not all type parameters assigned to same container"); | ||
INVARIANT( | ||
param_it->second.param_index == param_index++, |
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.
Eeep! Let's not have INVARIANT
conditions with side-effects, there are some compilation settings where the first arg is discarded
", ", | ||
[](const java_generic_parametert ¶m) { return param.get_name(); }); | ||
msg << ">"; | ||
std::string msg_str = msg.str(); |
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.
Debugging code accidentally left in?
@@ -187,7 +187,9 @@ SCENARIO( | |||
|
|||
const class_typet &derived_class_type = | |||
require_type::require_complete_java_implicitly_generic_class( | |||
derived_symbol.type, {"java::ContainsInnerClassGeneric::T"}); | |||
derived_symbol.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.
Double-check: do any of these tests exercise triple-nesting?
public class A<T> {
class B {
class C {
T field;
}
}
}
That sort of thing?
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 other test in that commit does: aec9e89#diff-157ff943932394172d454093024a926cR120
// Prepend existing parameters so choose those above any inherited | ||
if(is_java_generic_class_type(class_type)) | ||
{ | ||
const java_generic_class_typet::generic_typest &class_type_params = |
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 for "Make explicit type parameters shadow implicit ones with the same names" -- can you include a brief example of what you mean by precedence here? Are we talking class A<T> { class B<T> { T field // which T is that? } }
?
replacement_parameter_full_name); | ||
} | ||
// A replacement parameter was found, update the identifier | ||
const std::string &replacement_parameter_full_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.
Message: Sp congnative -> cognitive
{ | ||
find_and_replace_parameters( | ||
base.type(), implicit_generic_type_parameters); | ||
} | ||
|
||
class_symbol.type = new_class_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.
! This which was in the Code Cleanup commit suddenly looks like a bugfix -- the results of find_and_replace_parameters
would previously have been wrongly discarded, right? Can we test the fix?
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.
My assumption was that the thing we were changing was a reference to the same and this was just clarifying things. I'll check.
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.
It was. I've updated the commit message to make this clear.
fcda9ce
to
377bcc1
Compare
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.
Brilliant, thanks for putting so much effort into this one!
377bcc1
to
f5f62cf
Compare
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 PR failed Diffblue compatibility checks (cbmc commit: f5f62cf).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/120739813
Status will be re-evaluated on next push.
Common spurious failures include: the cbmc commit has disappeared in the mean time (e.g. in a force-push); the author is not in the list of contributors (e.g. first-time contributors); compatibility was already broken by an earlier merge.
Passing CI for Diffblue bump here: https://github.com/diffblue/test-gen/runs/177289127 |
const auto result = param_to_container.emplace( | ||
parameter.get_name(), container_paramt{container_index, param_index++}); | ||
INVARIANT( | ||
result.second, "Some but not all type parameters already mapped"); |
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 I understand the invariant message; there is no verb. 🐂
const auto param_it = param_to_container.find(parameter.get_name()); | ||
INVARIANT( | ||
param_it != param_to_container.end(), | ||
"Some but not all type parameters already mapped"); |
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.
🐂
"Some but not all type parameters already mapped"); | ||
INVARIANT( | ||
param_it->second.container_index == container_index, | ||
"Not all type parameters assigned to same container"); |
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.
🐂
|
||
class generic_parameter_specialization_mapt | ||
{ | ||
private: |
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 public section usually appears before the private one in cbmc
#include "expr2java.h" | ||
#include "java_types.h" | ||
|
||
class generic_parameter_specialization_mapt |
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 needs some documentation
|
||
template <typename ostream> | ||
ostream &operator<<( | ||
ostream &stm, |
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.
❓ Why does ostream
need to be a template parameter instead of being just std::ostream
?
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.
It could be restricted to std::ostream
but it doesn't need to be. I've added comment to that effect.
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 like this fixes some stuff and I can't see any problems. Therefore this has my approval.
}; | ||
|
||
template <typename ostream> | ||
ostream &operator<<( |
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 ostream
end in a t
like ostreamt
if it is a type?
@@ -1142,8 +1142,9 @@ void mark_java_implicitly_generic_class_type( | |||
{ | |||
const std::string qualified_class_name = "java::" + id2string(class_name); | |||
PRECONDITION(symbol_table.has_symbol(qualified_class_name)); | |||
// This will have its type changed |
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.
If you move the call to get_writeable_ref
into your new class_symbol.type = ...
line at the bottom, then this comment will no longer be necessary.
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.
Then we would have two lookups though...
Previously the code relied on the fact that class_type is a reference to class_symbol.type and so after a new type got copied assigned into class_symbol.type, class_type became a reference to the new value.
This will save time hunting for the cause of problems when unit tests don't initialise the config.
This will produce better error messages when tests fail.
This fixes the problem where we tried to unwind stacks in step that are not related, e.g. when a third generic class refers to two mutually recursive generic classes Instead stacks are created per scope (generic context) and unwound individually Also fixes problem where self-recursion isn't handled properly Add test that would have triggered invariant in get_recursively_instantiated_type
Previously they duplicated the names for the type parameters of the outer classes
Fixes problem where outer class type parameters take precedence over inner class ones Previously field would be given the type of the argument assigned to A::T, not B::T. class A<T> { class B<T> { T field; } }?
f5f62cf
to
186adb8
Compare
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 PR failed Diffblue compatibility checks (cbmc commit: 186adb8).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/121391281
Status will be re-evaluated on next push.
Common spurious failures include: the cbmc commit has disappeared in the mean time (e.g. in a force-push); the author is not in the list of contributors (e.g. first-time contributors); compatibility was already broken by an earlier merge.
This is a replacement for the closed PR #4913. It adopts a different approach as that approach was shown to be lacking.