diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-11-19 15:54:27 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-12-15 10:20:41 -0800 |
commit | d332bec19d47bfb7a2337248a80a2b8b938a9b40 (patch) | |
tree | e11f42cdb13fda931dc26f5fe82b6fb71b5c4022 | |
parent | 41ac8877500a0867f0c5c4145a56aff6299532e6 (diff) | |
download | mu-d332bec19d47bfb7a2337248a80a2b8b938a9b40.tar.gz |
infect immutability across recipes
If a product is contained-in some ingredient, then the caller will check the product for mutations as well. For example, consider this linked-list operation: b:address:list:number <- next a:address:list:number If 'a' is immutable in the surrounding recipe, you probably want 'b' to be immutable as well. You can achieve this by giving 'next' the following header (ignoring shape-shifting): recipe next a:address:list:number -> b:address:list:number/contained-in:a This is the theory, anyway. Rather to my surprise, this doesn't trigger any issues with existing code. That's probably too good to be true.
-rw-r--r-- | 060immutable.cc | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/060immutable.cc b/060immutable.cc index bbbcac96..8eaf8b98 100644 --- a/060immutable.cc +++ b/060immutable.cc @@ -129,10 +129,10 @@ void check_immutable_ingredients(recipe_ordinal r) { } void update_aliases(const instruction& inst, set<string>& current_ingredient_and_aliases) { + set<long long int> current_ingredient_indices = ingredient_indices(inst, current_ingredient_and_aliases); if (!contains_key(Recipe, inst.operation)) { // primitive recipe if (inst.operation == COPY) { - set<long long int> current_ingredient_indices = ingredient_indices(inst, current_ingredient_and_aliases); for (set<long long int>::iterator p = current_ingredient_indices.begin(); p != current_ingredient_indices.end(); ++p) { current_ingredient_and_aliases.insert(inst.products.at(*p).name); } @@ -140,9 +140,54 @@ void update_aliases(const instruction& inst, set<string>& current_ingredient_and } else { // defined recipe + set<long long int> contained_in_product_indices = scan_contained_in_product_indices(inst, current_ingredient_indices); + for (set<long long int>::iterator p = contained_in_product_indices.begin(); p != contained_in_product_indices.end(); ++p) { + if (*p < SIZE(inst.products)) + current_ingredient_and_aliases.insert(inst.products.at(*p).name); + } } } +set<long long int> scan_contained_in_product_indices(const instruction& inst, set<long long int>& ingredient_indices) { + set<string> selected_ingredient_names; + const recipe& callee = get(Recipe, inst.operation); + for (set<long long int>::iterator p = ingredient_indices.begin(); p != ingredient_indices.end(); ++p) + selected_ingredient_names.insert(callee.ingredients.at(*p).name); + set<long long int> result; + for (long long int i = 0; i < SIZE(callee.products); ++i) { + const reagent& current_product = callee.products.at(i); + const string_tree* contained_in_name = property(current_product, "contained-in"); + if (contained_in_name && selected_ingredient_names.find(contained_in_name->value) != selected_ingredient_names.end()) + result.insert(i); + } + return result; +} + +:(scenarios transform) +:(scenario immutability_infects_contained_in_variables) +% Hide_warnings = true; +container test-list [ + next:address:test-list +] +recipe main [ + local-scope + p:address:test-list <- new test-list:type + foo p +] +recipe foo p:address:test-list [ # p is immutable + local-scope + load-ingredients + p2:address:test-list <- test-next p # p2 is immutable + p3:address:address:test-list <- get-address *p2, next:offset # signal modification of p2 +] +recipe test-next x:address:test-list -> y:address:test-list/contained-in:x [ + local-scope + load-ingredients + y <- get *x, next:offset +] +$warn: 1 + +:(code) void check_immutable_ingredient_in_instruction(const instruction& inst, const set<string>& current_ingredient_and_aliases, const recipe& caller) { set<long long int> current_ingredient_indices = ingredient_indices(inst, current_ingredient_and_aliases); if (current_ingredient_indices.empty()) return; // ingredient not found in call @@ -212,7 +257,7 @@ set<long long int> ingredient_indices(const instruction& inst, const set<string> :(scenarios transform) :(scenario can_modify_contained_in_addresses) -#% Hide_warnings = true; +% Hide_warnings = true; container test-list [ next:address:test-list ] |