about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-02-26 17:36:22 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-02-26 17:36:22 -0800
commit5e1f318d5097dbe5443ffad3e258e950a062a5fe (patch)
tree107163d7b8b10fd40d24128b5f2266f51d76129b
parente616059d70926a8712134072988edb6ae0cae17a (diff)
downloadmu-5e1f318d5097dbe5443ffad3e258e950a062a5fe.tar.gz
2715 - bugfix: directly modifying ingredients
-rw-r--r--060immutable.cc24
1 files changed, 24 insertions, 0 deletions
diff --git a/060immutable.cc b/060immutable.cc
index d3b7278a..532746a5 100644
--- a/060immutable.cc
+++ b/060immutable.cc
@@ -48,6 +48,20 @@ container d1 [
 ]
 $error: 0
 
+:(scenario cannot_modify_immutable_ingredients)
+% Hide_errors = true;
+recipe main [
+  local-scope
+  x:address:shared:number <- new number:type
+  foo x
+]
+recipe foo x:address:shared:number [
+  local-scope
+  load-ingredients
+  *x <- copy 34
+]
++error: foo: cannot modify ingredient x in instruction '*x <- copy 34' because it's not also a product of foo
+
 :(scenario cannot_take_address_inside_immutable_ingredients)
 % Hide_errors = true;
 recipe main [
@@ -227,6 +241,15 @@ recipe test-next x:address:shared:test-list -> y:address:shared:test-list/contai
 
 :(code)
 void check_immutable_ingredient_in_instruction(const instruction& inst, const set<string>& current_ingredient_and_aliases, const string& original_ingredient_name, const recipe& caller) {
+  // first check if the instruction is directly modifying something it shouldn't
+  for (long long int i = 0; i < SIZE(inst.products); ++i) {
+    if (has_property(inst.products.at(i), "lookup")
+        && current_ingredient_and_aliases.find(inst.products.at(i).name) != current_ingredient_and_aliases.end()) {
+      raise << maybe(caller.name) << "cannot modify ingredient " << inst.products.at(i).name << " in instruction '" << to_string(inst) << "' because it's not also a product of " << caller.name << '\n' << end();
+      return;
+    }
+  }
+  // check if there's any indirect modification going on
   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
   for (set<long long int>::iterator p = current_ingredient_indices.begin(); p != current_ingredient_indices.end(); ++p) {
@@ -237,6 +260,7 @@ void check_immutable_ingredient_in_instruction(const instruction& inst, const se
     if (!contains_key(Recipe, inst.operation)) {
       // primitive recipe
       if (inst.operation == GET_ADDRESS || inst.operation == INDEX_ADDRESS) {
+        // only reason to use get-address or index-address is to modify, so stop right there
         if (current_ingredient_name == original_ingredient_name)
           raise << maybe(caller.name) << "cannot modify ingredient " << current_ingredient_name << " after instruction '" << to_string(inst) << "' because it's not also a product of " << caller.name << '\n' << end();
         else