about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-02-15 13:52:51 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-02-15 14:07:23 -0800
commit4637d58f6c4777f9643f73de859af23c38acca2c (patch)
treeaed44d16e0ae6a7961351d964189e3cbca4d8706
parentf592d8629f3fddaebff4abece8f92e57e9379418 (diff)
downloadmu-4637d58f6c4777f9643f73de859af23c38acca2c.tar.gz
2661 - warn if a reply doesn't match recipe header
Thanks Nicolas Léveillé for running up against this bug:
  https://news.ycombinator.com/item?id=11094837

(Also noticed and fixed several subsidiary issues. This whole aspect
doesn't seem fully baked yet.)
-rw-r--r--036call_reply.cc3
-rw-r--r--056recipe_header.cc21
-rw-r--r--edit/003-shortcuts.mu3
-rw-r--r--sandbox/003-shortcuts.mu3
4 files changed, 23 insertions, 7 deletions
diff --git a/036call_reply.cc b/036call_reply.cc
index d24eb98a..eb4c1aba 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -105,8 +105,9 @@ void check_types_of_reply_instructions(recipe_ordinal r) {
             raise_error << maybe(caller.name) << "too few ingredients in '" << caller_instruction.to_string() << "'\n" << end();
             goto finish_reply_check;
           }
-          if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).name != caller_instruction.ingredients.at(ingredient_index).name)
+          if (!is_dummy(caller_instruction.products.at(i)) && !is_literal(caller_instruction.ingredients.at(ingredient_index)) && caller_instruction.products.at(i).name != caller_instruction.ingredients.at(ingredient_index).name) {
             raise_error << maybe(caller.name) << "'" << caller_instruction.to_string() << "' should write to " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
+          }
         }
       }
       finish_reply_check:;
diff --git a/056recipe_header.cc b/056recipe_header.cc
index baacaf8f..f55c2ba8 100644
--- a/056recipe_header.cc
+++ b/056recipe_header.cc
@@ -286,19 +286,32 @@ Transform.push_back(check_reply_instructions_against_header);  // idempotent
 :(code)
 void check_reply_instructions_against_header(const recipe_ordinal r) {
   const recipe& caller_recipe = get(Recipe, r);
-  if (caller_recipe.products.empty()) return;
+  if (!caller_recipe.has_header) return;
   trace(9991, "transform") << "--- checking reply instructions against header for " << caller_recipe.name << end();
-//?   cerr << "--- checking reply instructions against header for " << caller_recipe.name << '\n';
   for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) {
     const instruction& inst = caller_recipe.steps.at(i);
     if (inst.name != "reply") continue;
-    for (long long int i = 0; i < min(SIZE(caller_recipe.products), SIZE(inst.ingredients)); ++i) {
+    if (SIZE(caller_recipe.products) != SIZE(inst.ingredients)) {
+      raise_error << maybe(caller_recipe.name) << "replied with the wrong number of products at '" << inst.to_string() << "'\n" << end();
+      continue;
+    }
+    for (long long int i = 0; i < SIZE(caller_recipe.products); ++i) {
       if (!types_match(caller_recipe.products.at(i), inst.ingredients.at(i)))
         raise_error << maybe(caller_recipe.name) << "replied with the wrong type at '" << inst.to_string() << "'\n" << end();
     }
   }
 }
 
+:(scenario recipe_headers_are_checked_2)
+% Hide_errors = true;
+recipe add2 x:number, y:number [
+  local-scope
+  load-ingredients
+  z:address:number <- copy 0/unsafe
+  reply z
+]
++error: add2: replied with the wrong number of products at 'reply z'
+
 :(scenario recipe_headers_check_for_duplicate_names)
 % Hide_errors = true;
 recipe add2 x:number, x:number -> z:number [
@@ -415,7 +428,7 @@ void fill_in_reply_ingredients(recipe_ordinal r) {
   trace(9991, "transform") << "--- fill in reply ingredients from header for recipe " << caller_recipe.name << end();
   for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) {
     instruction& inst = caller_recipe.steps.at(i);
-    if (inst.name == "reply" && inst.ingredients.empty())
+    if (inst.name == "reply")
       add_header_products(inst, caller_recipe);
   }
   // fall through reply
diff --git a/edit/003-shortcuts.mu b/edit/003-shortcuts.mu
index 12de1f70..f6c762a6 100644
--- a/edit/003-shortcuts.mu
+++ b/edit/003-shortcuts.mu
@@ -2310,9 +2310,10 @@ after <scroll-up> [
 # takes a pointer into the doubly-linked list, scans back to before start of
 # previous *wrapped* line
 # beware: never return null pointer
-recipe before-previous-line curr:address:shared:duplex-list:character, editor:address:shared:editor-data -> curr:address:shared:duplex-list:character [
+recipe before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
   local-scope
   load-ingredients
+  curr:address:shared:duplex-list:character <- copy in
   c:character <- get *curr, value:offset
   # compute max, number of characters to skip
   #   1 + len%(width-1)
diff --git a/sandbox/003-shortcuts.mu b/sandbox/003-shortcuts.mu
index 12de1f70..f6c762a6 100644
--- a/sandbox/003-shortcuts.mu
+++ b/sandbox/003-shortcuts.mu
@@ -2310,9 +2310,10 @@ after <scroll-up> [
 # takes a pointer into the doubly-linked list, scans back to before start of
 # previous *wrapped* line
 # beware: never return null pointer
-recipe before-previous-line curr:address:shared:duplex-list:character, editor:address:shared:editor-data -> curr:address:shared:duplex-list:character [
+recipe before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
   local-scope
   load-ingredients
+  curr:address:shared:duplex-list:character <- copy in
   c:character <- get *curr, value:offset
   # compute max, number of characters to skip
   #   1 + len%(width-1)