Skip to content

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

Conversation

NathanJPhillips
Copy link
Contributor

@NathanJPhillips NathanJPhillips commented Jul 19, 2019

This is a replacement for the closed PR #4913. It adopts a different approach as that approach was shown to be lacking.

  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • N/A My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@NathanJPhillips NathanJPhillips requested a review from smowton July 19, 2019 15:34
@NathanJPhillips NathanJPhillips force-pushed the bugfix/generic_parameter_specialization_map branch 3 times, most recently from d1c2855 to 7c01b9a Compare July 19, 2019 17:49
@NathanJPhillips NathanJPhillips changed the title Fix generic_parameter_specialization_map in the presence of non-symmetric generic recursion Fix generic_parameter_specialization_map in the presence of non-symmetric generic recursion [TG-7815] Jul 22, 2019
}
const auto *array_element_type =
type_try_dynamic_cast<pointer_typet>(java_array_element_type(*subtype));
if(array_element_type == nullptr)
Copy link
Contributor

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 \
Copy link
Contributor

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> &params = container_to_params[elt.second.first];
Copy link
Contributor

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;
}

Copy link
Contributor

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 &parameter_name = parameter->get_name();
irep_idt parameter_name = parameter->get_name();
Copy link
Contributor

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

Copy link
Contributor Author

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.
Copy link
Contributor

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
Copy link
Contributor

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

@NathanJPhillips NathanJPhillips force-pushed the bugfix/generic_parameter_specialization_map branch 2 times, most recently from 833e1b7 to fcda9ce Compare July 24, 2019 17:40
@codecov-io
Copy link

codecov-io commented Jul 24, 2019

Codecov Report

Merging #4929 into develop will increase coverage by 0.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             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
Impacted Files Coverage Δ
jbmc/src/java_bytecode/select_pointer_type.h 100% <ø> (ø) ⬆️
src/util/simplify_expr_int.cpp 80.49% <ø> (ø) ⬆️
..._bytecode/generic_parameter_specialization_map.cpp 100% <100%> (ø)
jbmc/unit/java-testing-utils/require_type.cpp 89.93% <100%> (+0.27%) ⬆️
...code/generic_parameter_specialization_map_keys.cpp 100% <100%> (ø) ⬆️
...enerics/parse_generic_class_with_inner_classes.cpp 100% <100%> (ø) ⬆️
.../src/java_bytecode/java_bytecode_convert_class.cpp 94.73% <100%> (+0.15%) ⬆️
jbmc/src/java_bytecode/select_pointer_type.cpp 100% <100%> (ø) ⬆️
src/util/pointer_offset_size.cpp 94.53% <100%> (+0.01%) ⬆️
jbmc/src/java_bytecode/java_types.h 100% <100%> (ø) ⬆️
... and 8 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9643ec2...186adb8. Read the comment docs.

Copy link
Contributor

@allredj allredj left a 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.

Copy link
Contributor

@allredj allredj left a 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++,
Copy link
Contributor

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 &param) { return param.get_name(); });
msg << ">";
std::string msg_str = msg.str();
Copy link
Contributor

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,
Copy link
Contributor

@smowton smowton Jul 25, 2019

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?

Copy link
Contributor Author

@NathanJPhillips NathanJPhillips Jul 25, 2019

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 =
Copy link
Contributor

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 =
Copy link
Contributor

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;
Copy link
Contributor

@smowton smowton Jul 25, 2019

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

@NathanJPhillips NathanJPhillips force-pushed the bugfix/generic_parameter_specialization_map branch from fcda9ce to 377bcc1 Compare July 25, 2019 14:57
Copy link
Contributor

@smowton smowton left a 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!

@NathanJPhillips NathanJPhillips force-pushed the bugfix/generic_parameter_specialization_map branch from 377bcc1 to f5f62cf Compare July 25, 2019 15:53
Copy link
Contributor

@allredj allredj left a 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.

@NathanJPhillips
Copy link
Contributor Author

Passing CI for Diffblue bump here: https://github.com/diffblue/test-gen/runs/177289127

@thomasspriggs thomasspriggs self-assigned this Jul 26, 2019
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");
Copy link
Contributor

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");
Copy link
Contributor

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");
Copy link
Contributor

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:
Copy link
Contributor

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
Copy link
Contributor

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,
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

@thomasspriggs thomasspriggs left a 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<<(
Copy link
Contributor

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
Copy link
Contributor

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.

Copy link
Contributor Author

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...

Add space between pre-checks and action
Remove space between abbreviations and their usage
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; } }?
@NathanJPhillips NathanJPhillips force-pushed the bugfix/generic_parameter_specialization_map branch from f5f62cf to 186adb8 Compare July 31, 2019 09:35
Copy link
Contributor

@allredj allredj left a 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.

@NathanJPhillips NathanJPhillips merged commit 639b864 into diffblue:develop Jul 31, 2019
@NathanJPhillips NathanJPhillips deleted the bugfix/generic_parameter_specialization_map branch July 31, 2019 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants