about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-11-06 11:17:39 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-11-06 11:53:10 -0800
commit571791babc25dce11c188ece3530817a1c80391c (patch)
treea45e614375028d73e7392e19442d9b44be321109
parent7cca315fb435234adae3c46c65594feccb9d1fbd (diff)
downloadmu-571791babc25dce11c188ece3530817a1c80391c.tar.gz
3637 - better 'missing type ingredient' errors
Programming languages need some higher-level language construct that's
neither an interface nor a class nor an object but a *collection of
mutually recursive functions with a well-defined set of entry points and
common ingredients. Perhaps the solution here is the Haskell "save your
boilerplate" paper. For now I'm going to include the purpose in
auxiliary variable names that aren't really necessary for the core
processing of a function.

Thanks Caleb Couch for reporting this issue.
-rw-r--r--030container.cc40
-rw-r--r--033exclusive_container.cc6
-rw-r--r--036refcount.cc74
-rw-r--r--055shape_shifting_container.cc42
4 files changed, 81 insertions, 81 deletions
diff --git a/030container.cc b/030container.cc
index 4519e347..52c3c1ae 100644
--- a/030container.cc
+++ b/030container.cc
@@ -184,24 +184,24 @@ void compute_container_sizes(const recipe_ordinal r) {
     instruction& inst = caller.steps.at(i);
     trace(9993, "transform") << "- compute container sizes for " << to_string(inst) << end();
     for (int i = 0;  i < SIZE(inst.ingredients);  ++i)
-      compute_container_sizes(inst.ingredients.at(i));
+      compute_container_sizes(inst.ingredients.at(i), " in '"+to_original_string(inst)+"'");
     for (int i = 0;  i < SIZE(inst.products);  ++i)
-      compute_container_sizes(inst.products.at(i));
+      compute_container_sizes(inst.products.at(i), " in '"+to_original_string(inst)+"'");
   }
 }
 
-void compute_container_sizes(reagent& r) {
+void compute_container_sizes(reagent& r, const string& location_for_error_messages) {
   expand_type_abbreviations(r.type);
   if (is_literal(r) || is_dummy(r)) return;
   reagent rcopy = r;
   // Compute Container Size(reagent rcopy)
   set<type_tree> pending_metadata;  // might actually be faster to just convert to string rather than compare type_tree directly; so far the difference is negligible
-  compute_container_sizes(rcopy.type, pending_metadata);
+  compute_container_sizes(rcopy.type, pending_metadata, location_for_error_messages);
   if (contains_key(Container_metadata, rcopy.type))
     r.metadata = get(Container_metadata, rcopy.type);
 }
 
-void compute_container_sizes(const type_tree* type, set<type_tree>& pending_metadata) {
+void compute_container_sizes(const type_tree* type, set<type_tree>& pending_metadata, const string& location_for_error_messages) {
   if (!type) return;
   trace(9993, "transform") << "compute container sizes for " << to_string(type) << end();
   if (contains_key(Container_metadata, type)) return;
@@ -210,14 +210,14 @@ void compute_container_sizes(const type_tree* type, set<type_tree>& pending_meta
   if (!type->atom) {
     assert(type->left->atom);
     if (type->left->name == "address") {
-      compute_container_sizes(type->right, pending_metadata);
+      compute_container_sizes(type->right, pending_metadata, location_for_error_messages);
     }
     else if (type->left->name == "array") {
       const type_tree* element_type = type->right;
       // hack: support both array:num:3 and array:address:num
       if (!element_type->atom && element_type->right && element_type->right->atom && is_integer(element_type->right->name))
         element_type = element_type->left;
-      compute_container_sizes(element_type, pending_metadata);
+      compute_container_sizes(element_type, pending_metadata, location_for_error_messages);
     }
     // End compute_container_sizes Non-atom Cases
     return;
@@ -226,12 +226,12 @@ void compute_container_sizes(const type_tree* type, set<type_tree>& pending_meta
   if (!contains_key(Type, type->value)) return;  // error raised elsewhere
   type_info& info = get(Type, type->value);
   if (info.kind == CONTAINER) {
-    compute_container_sizes(info, type, pending_metadata);
+    compute_container_sizes(info, type, pending_metadata, location_for_error_messages);
   }
   // End compute_container_sizes Atom Cases
 }
 
-void compute_container_sizes(const type_info& container_info, const type_tree* full_type, set<type_tree>& pending_metadata) {
+void compute_container_sizes(const type_info& container_info, const type_tree* full_type, set<type_tree>& pending_metadata, const string& location_for_error_messages) {
   assert(container_info.kind == CONTAINER);
   // size of a container is the sum of the sizes of its element
   // (So it can only contain arrays if they're static and include their
@@ -240,7 +240,7 @@ void compute_container_sizes(const type_info& container_info, const type_tree* f
   for (int i = 0;  i < SIZE(container_info.elements);  ++i) {
     reagent/*copy*/ element = container_info.elements.at(i);
     // Compute Container Size(element, full_type)
-    compute_container_sizes(element.type, pending_metadata);
+    compute_container_sizes(element.type, pending_metadata, location_for_error_messages);
     metadata.offset.push_back(metadata.size);  // save previous size as offset
     metadata.size += size_of(element.type);
   }
@@ -290,7 +290,7 @@ void test_container_sizes() {
   reagent r("x:point");
   CHECK(!contains_key(Container_metadata, r.type));
   // scan
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   // the reagent we scanned knows its size
   CHECK_EQ(r.metadata.size, 2);
   // the global table also knows its size
@@ -303,7 +303,7 @@ void test_container_sizes_through_aliases() {
   put(Type_abbreviations, "pt", new_type_tree("point"));
   reagent r("x:pt");
   // scan
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   // the reagent we scanned knows its size
   CHECK_EQ(r.metadata.size, 2);
   // the global table also knows its size
@@ -316,7 +316,7 @@ void test_container_sizes_nested() {
   reagent r("x:point-number");
   CHECK(!contains_key(Container_metadata, r.type));
   // scan
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   // the reagent we scanned knows its size
   CHECK_EQ(r.metadata.size, 3);
   // the global table also knows its size
@@ -331,7 +331,7 @@ void test_container_sizes_recursive() {
       "  y:address:foo\n"
       "]\n");
   reagent r("x:foo");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK_EQ(r.metadata.size, 2);
 }
 
@@ -341,7 +341,7 @@ void test_container_sizes_from_address() {
   CHECK(!contains_key(Container_metadata, container.type));
   // scanning an address to the container precomputes the size of the container
   reagent r("x:address:point");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK(contains_key(Container_metadata, container.type));
   CHECK_EQ(get(Container_metadata, container.type).size, 2);
 }
@@ -352,7 +352,7 @@ void test_container_sizes_from_array() {
   CHECK(!contains_key(Container_metadata, container.type));
   // scanning an array of the container precomputes the size of the container
   reagent r("x:array:point");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK(contains_key(Container_metadata, container.type));
   CHECK_EQ(get(Container_metadata, container.type).size, 2);
 }
@@ -363,7 +363,7 @@ void test_container_sizes_from_address_to_array() {
   CHECK(!contains_key(Container_metadata, container.type));
   // scanning an address to an array of the container precomputes the size of the container
   reagent r("x:address:array:point");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK(contains_key(Container_metadata, container.type));
   CHECK_EQ(get(Container_metadata, container.type).size, 2);
 }
@@ -374,7 +374,7 @@ void test_container_sizes_from_static_array() {
   int old_size = SIZE(Container_metadata);
   // scanning an address to an array of the container precomputes the size of the container
   reagent r("x:array:point:10");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK(contains_key(Container_metadata, container.type));
   CHECK_EQ(get(Container_metadata, container.type).size, 2);
   // no non-container types precomputed
@@ -387,7 +387,7 @@ void test_container_sizes_from_address_to_static_array() {
   int old_size = SIZE(Container_metadata);
   // scanning an address to an array of the container precomputes the size of the container
   reagent r("x:address:array:point:10");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK(contains_key(Container_metadata, container.type));
   CHECK_EQ(get(Container_metadata, container.type).size, 2);
   // no non-container types precomputed
@@ -400,7 +400,7 @@ void test_container_sizes_from_repeated_address_and_array_types() {
   int old_size = SIZE(Container_metadata);
   // scanning repeated address and array types modifying the container precomputes the size of the container
   reagent r("x:address:array:address:array:point:10");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK(contains_key(Container_metadata, container.type));
   CHECK_EQ(get(Container_metadata, container.type).size, 2);
   // no non-container types precomputed
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index 800f1a86..88b33639 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -37,11 +37,11 @@ if (t.kind == EXCLUSIVE_CONTAINER) {
 }
 :(before "End compute_container_sizes Atom Cases")
 if (info.kind == EXCLUSIVE_CONTAINER) {
-  compute_exclusive_container_sizes(info, type, pending_metadata);
+  compute_exclusive_container_sizes(info, type, pending_metadata, location_for_error_messages);
 }
 
 :(code)
-void compute_exclusive_container_sizes(const type_info& exclusive_container_info, const type_tree* full_type, set<type_tree>& pending_metadata) {
+void compute_exclusive_container_sizes(const type_info& exclusive_container_info, const type_tree* full_type, set<type_tree>& pending_metadata, const string& location_for_error_messages) {
   // size of an exclusive container is the size of its largest variant
   // (So, like containers, it can only contain arrays if they're static and
   // include their length in the type.)
@@ -49,7 +49,7 @@ void compute_exclusive_container_sizes(const type_info& exclusive_container_info
   for (int i = 0;  i < SIZE(exclusive_container_info.elements);  ++i) {
     reagent/*copy*/ element = exclusive_container_info.elements.at(i);
     // Compute Exclusive Container Size(element, full_type)
-    compute_container_sizes(element.type, pending_metadata);
+    compute_container_sizes(element.type, pending_metadata, location_for_error_messages);
     int variant_size = size_of(element);
     if (variant_size > metadata.size) metadata.size = variant_size;
   }
diff --git a/036refcount.cc b/036refcount.cc
index 009defa1..267eb364 100644
--- a/036refcount.cc
+++ b/036refcount.cc
@@ -290,65 +290,65 @@ void compute_container_address_offsets(const recipe_ordinal r) {
     instruction& inst = caller.steps.at(i);
     trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end();
     for (int i = 0;  i < SIZE(inst.ingredients);  ++i)
-      compute_container_address_offsets(inst.ingredients.at(i));
+      compute_container_address_offsets(inst.ingredients.at(i), " in '"+to_original_string(inst)+"'");
     for (int i = 0;  i < SIZE(inst.products);  ++i)
-      compute_container_address_offsets(inst.products.at(i));
+      compute_container_address_offsets(inst.products.at(i), " in '"+to_original_string(inst)+"'");
   }
 }
 
-void compute_container_address_offsets(reagent& r) {
+void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) {
   if (is_literal(r) || is_dummy(r)) return;
-  compute_container_address_offsets(r.type);
+  compute_container_address_offsets(r.type, location_for_error_messages);
   if (contains_key(Container_metadata, r.type))
     r.metadata = get(Container_metadata, r.type);
 }
 
 // the recursive structure of this function needs to exactly match
 // compute_container_sizes
-void compute_container_address_offsets(const type_tree* type) {
+void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) {
   if (!type) return;
   if (!type->atom) {
     assert(type->left->atom);
     if (type->left->name == "address") {
-      compute_container_address_offsets(type->right);
+      compute_container_address_offsets(type->right, location_for_error_messages);
     }
     else if (type->left->name == "array") {
       const type_tree* element_type = type->right;
       // hack: support both array:num:3 and array:address:num
       if (!element_type->atom && element_type->right && element_type->right->atom && is_integer(element_type->right->name))
         element_type = element_type->left;
-      compute_container_address_offsets(element_type);
+      compute_container_address_offsets(element_type, location_for_error_messages);
     }
     // End compute_container_address_offsets Non-atom Cases
   }
   if (!contains_key(Type, root_type(type)->value)) return;  // error raised elsewhere
   type_info& info = get(Type, root_type(type)->value);
   if (info.kind == CONTAINER) {
-    compute_container_address_offsets(info, type);
+    compute_container_address_offsets(info, type, location_for_error_messages);
   }
   if (info.kind == EXCLUSIVE_CONTAINER) {
-    compute_exclusive_container_address_offsets(info, type);
+    compute_exclusive_container_address_offsets(info, type, location_for_error_messages);
   }
 }
 
-void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type) {
+void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) {
   container_metadata& metadata = get(Container_metadata, full_type);
   if (!metadata.address.empty()) return;
   trace(9994, "transform") << "compute address offsets for container " << container_info.name << end();
-  append_addresses(0, full_type, metadata.address, set<tag_condition_info>());
+  append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages);
 }
 
-void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type) {
+void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) {
   container_metadata& metadata = get(Container_metadata, full_type);
   trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end();
   for (int tag = 0;  tag < SIZE(exclusive_container_info.elements);  ++tag) {
     set<tag_condition_info> key;
     key.insert(tag_condition_info(/*tag is at offset*/0, tag));
-    append_addresses(/*skip tag offset*/1, variant_type(full_type, tag).type, metadata.address, key);
+    append_addresses(/*skip tag offset*/1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages);
   }
 }
 
-void append_addresses(int base_offset, const type_tree* type, map<set<tag_condition_info>, set<address_element_info> >& out, const set<tag_condition_info>& key) {
+void append_addresses(int base_offset, const type_tree* type, map<set<tag_condition_info>, set<address_element_info> >& out, const set<tag_condition_info>& key, const string& location_for_error_messages) {
   if (is_mu_address(type)) {
     get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*type->right)));
     return;
@@ -366,7 +366,7 @@ void append_addresses(int base_offset, const type_tree* type, map<set<tag_condit
         ++curr_offset;
       }
       else if (is_mu_container(element)) {
-        append_addresses(curr_offset, element.type, out, key);
+        append_addresses(curr_offset, element.type, out, key, location_for_error_messages);
         curr_offset += size_of(element);
       }
       else if (is_mu_exclusive_container(element)) {
@@ -376,7 +376,7 @@ void append_addresses(int base_offset, const type_tree* type, map<set<tag_condit
           set<tag_condition_info> new_key = key;
           new_key.insert(tag_condition_info(curr_offset, tag));
           if (!contains_key(out, new_key))
-            append_addresses(curr_offset+/*skip tag*/1, variant_type(element.type, tag).type, out, new_key);
+            append_addresses(curr_offset+/*skip tag*/1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages);
         }
         curr_offset += size_of(element);
       }
@@ -391,7 +391,7 @@ void append_addresses(int base_offset, const type_tree* type, map<set<tag_condit
       set<tag_condition_info> new_key = key;
       new_key.insert(tag_condition_info(base_offset, tag));
       if (!contains_key(out, new_key))
-        append_addresses(base_offset+/*skip tag*/1, variant_type(type, tag).type, out, new_key);
+        append_addresses(base_offset+/*skip tag*/1, variant_type(type, tag).type, out, new_key, location_for_error_messages);
     }
   }
 }
@@ -409,9 +409,9 @@ void test_container_address_offsets_empty() {
   int old_size = SIZE(Container_metadata);
   // define a container with no addresses
   reagent r("x:point");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // scan
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
@@ -431,9 +431,9 @@ void test_container_address_offsets() {
       "  x:address:num\n"
       "]\n");
   reagent r("x:foo");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // scan
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
@@ -464,12 +464,12 @@ void test_container_address_offsets_2() {
       "  y:address:num\n"
       "]\n");
   reagent r("x:foo");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scan
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // compute_container_address_offsets creates no new entries
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // the reagent we scanned knows it has an address at offset 1
@@ -501,12 +501,12 @@ void test_container_address_offsets_nested() {
       "  f:foo\n"  // nested container containing address
       "]\n");
   reagent r("x:bar");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains entries for bar and included types: point and foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
   // scan
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // the reagent we scanned knows it has an address at offset 2
   CHECK_EQ(SIZE(r.metadata.address), 1);
   CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
@@ -533,12 +533,12 @@ void test_container_address_offsets_from_address() {
       "  x:address:num\n"
       "]\n");
   reagent r("x:address:foo");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scan an address to the container
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // compute_container_address_offsets creates no new entries
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scanning precomputed metadata for the container
@@ -558,12 +558,12 @@ void test_container_address_offsets_from_array() {
       "  x:address:num\n"
       "]\n");
   reagent r("x:array:foo");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scan an array of the container
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // compute_container_address_offsets creates no new entries
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scanning precomputed metadata for the container
@@ -583,12 +583,12 @@ void test_container_address_offsets_from_address_to_array() {
       "  x:address:num\n"
       "]\n");
   reagent r("x:address:array:foo");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scan an address to an array of the container
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // compute_container_address_offsets creates no new entries
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scanning precomputed metadata for the container
@@ -608,12 +608,12 @@ void test_container_address_offsets_from_static_array() {
       "  x:address:num\n"
       "]\n");
   reagent r("x:array:foo:10");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scan a static array of the container
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // compute_container_address_offsets creates no new entries
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scanning precomputed metadata for the container
@@ -633,12 +633,12 @@ void test_container_address_offsets_from_address_to_static_array() {
       "  x:address:num\n"
       "]\n");
   reagent r("x:address:array:foo:10");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scan an address to a static array of the container
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // compute_container_address_offsets creates no new entries
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scanning precomputed metadata for the container
@@ -659,11 +659,11 @@ void test_container_address_offsets_from_repeated_address_and_array_types() {
       "]\n");
   // scan a deep nest of 'address' and 'array' types modifying a container
   reagent r("x:address:array:address:address:array:foo:10");
-  compute_container_sizes(r);  // need to first pre-populate the metadata
+  compute_container_sizes(r, "");  // need to first pre-populate the metadata
   // global metadata contains just the entry for foo
   // no entries for non-container types or other junk
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
-  compute_container_address_offsets(r);
+  compute_container_address_offsets(r, "");
   // compute_container_address_offsets creates no new entries
   CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
   // scanning precomputed metadata for the container
diff --git a/055shape_shifting_container.cc b/055shape_shifting_container.cc
index 33746c46..044e7089 100644
--- a/055shape_shifting_container.cc
+++ b/055shape_shifting_container.cc
@@ -286,20 +286,20 @@ def main [
 +mem: storing 1 in location 4
 
 :(before "End element_type Special-cases")
-replace_type_ingredients(element, type, info);
+replace_type_ingredients(element, type, info, " while computing element type of container");
 :(before "Compute Container Size(element, full_type)")
-replace_type_ingredients(element, full_type, container_info);
+replace_type_ingredients(element, full_type, container_info, location_for_error_messages);
 :(before "Compute Exclusive Container Size(element, full_type)")
-replace_type_ingredients(element, full_type, exclusive_container_info);
+replace_type_ingredients(element, full_type, exclusive_container_info, location_for_error_messages);
 :(before "Compute Container Address Offset(element)")
-replace_type_ingredients(element, type, info);
+replace_type_ingredients(element, type, info, location_for_error_messages);
 if (contains_type_ingredient(element)) return;  // error raised elsewhere
 
 :(code)
-void replace_type_ingredients(reagent& element, const type_tree* caller_type, const type_info& info) {
+void replace_type_ingredients(reagent& element, const type_tree* caller_type, const type_info& info, const string& location_for_error_messages) {
   if (contains_type_ingredient(element)) {
     if (!caller_type->right)
-      raise << "illegal type " << names_to_string(caller_type) << " seems to be missing a type ingredient or three\n" << end();
+      raise << "illegal type " << names_to_string(caller_type) << " seems to be missing a type ingredient or three" << location_for_error_messages << '\n' << end();
     replace_type_ingredients(element.type, caller_type->right, info);
   }
 }
@@ -479,7 +479,7 @@ def main [
   10:foo:point <- merge 14, 15, 16
   1:num <- get 10:foo, 1:offset
 ]
-+error: illegal type "foo" seems to be missing a type ingredient or three
++error: illegal type "foo" seems to be missing a type ingredient or three in '1:num <- get 10:foo, 1:offset'
 
 //:: fix up previous layers
 
@@ -491,11 +491,11 @@ def main [
 const type_tree* root = root_type(type);
 type_info& info = get(Type, root->value);
 if (info.kind == CONTAINER) {
-  compute_container_sizes(info, type, pending_metadata);
+  compute_container_sizes(info, type, pending_metadata, location_for_error_messages);
   return;
 }
 if (info.kind == EXCLUSIVE_CONTAINER) {
-  compute_exclusive_container_sizes(info, type, pending_metadata);
+  compute_exclusive_container_sizes(info, type, pending_metadata, location_for_error_messages);
   return;
 }
 
@@ -506,7 +506,7 @@ void test_container_sizes_shape_shifting_container() {
       "  y:_t\n"
       "]\n");
   reagent r("x:foo:point");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK_EQ(r.metadata.size, 3);
 }
 
@@ -516,10 +516,10 @@ void test_container_sizes_shape_shifting_exclusive_container() {
       "  y:_t\n"
       "]\n");
   reagent r("x:foo:point");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK_EQ(r.metadata.size, 3);
   reagent r2("x:foo:num");
-  compute_container_sizes(r2);
+  compute_container_sizes(r2, "");
   CHECK_EQ(r2.metadata.size, 2);
 }
 
@@ -529,7 +529,7 @@ void test_container_sizes_compound_type_ingredient() {
       "  y:_t\n"
       "]\n");
   reagent r("x:foo:&:point");
-  compute_container_sizes(r);
+  compute_container_sizes(r, "");
   CHECK_EQ(r.metadata.size, 2);
   // scan also pre-computes metadata for type ingredient
   reagent point("x:point");
@@ -543,7 +543,7 @@ void test_container_sizes_recursive_shape_shifting_container() {
       "  y:&:foo:_t\n"
       "]\n");
   reagent r2("x:foo:num");
-  compute_container_sizes(r2);
+  compute_container_sizes(r2, "");
   CHECK_EQ(r2.metadata.size, 2);
 }
 
@@ -551,11 +551,11 @@ void test_container_sizes_recursive_shape_shifting_container() {
 const type_tree* root = root_type(type);
 type_info& info = get(Type, root->value);
 if (info.kind == CONTAINER) {
-  compute_container_address_offsets(info, type);
+  compute_container_address_offsets(info, type, location_for_error_messages);
   return;
 }
 if (info.kind == EXCLUSIVE_CONTAINER) {
-  compute_exclusive_container_address_offsets(info, type);
+  compute_exclusive_container_address_offsets(info, type, location_for_error_messages);
   return;
 }
 
@@ -566,8 +566,8 @@ void test_container_address_offsets_in_shape_shifting_container() {
       "  y:_t\n"
       "]\n");
   reagent r("x:foo:&:num");
-  compute_container_sizes(r);
-  compute_container_address_offsets(r);
+  compute_container_sizes(r, "");
+  compute_container_address_offsets(r, "");
   CHECK_EQ(SIZE(r.metadata.address), 1);
   CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
   set<address_element_info>& offset_info = get(r.metadata.address, set<tag_condition_info>());
@@ -588,8 +588,8 @@ void test_container_address_offsets_in_nested_shape_shifting_container() {
       "]\n");
   reagent r("x:bar:&:num");
   CLEAR_TRACE;
-  compute_container_sizes(r);
-  compute_container_address_offsets(r);
+  compute_container_sizes(r, "");
+  compute_container_address_offsets(r, "");
   CHECK_EQ(SIZE(r.metadata.address), 1);
   CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
   set<address_element_info>& offset_info = get(r.metadata.address, set<tag_condition_info>());
@@ -685,6 +685,6 @@ def main [
 :(before "End variant_type Special-cases")
 if (contains_type_ingredient(element)) {
   if (!type->right)
-    raise << "illegal type " << to_string(type) << " seems to be missing a type ingredient or three\n" << end();
+    raise << "illegal type " << to_string(type) << " seems to be missing a type ingredient or three while computing variant type of exclusive-container\n" << end();
   replace_type_ingredients(element.type, type->right, info);
 }