about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-06-09 08:59:33 -0700
committerKartik Agaram <vc@akkartik.com>2018-06-09 09:50:35 -0700
commit3f34ac9369978b396d00a4fd02c9fb06b8eea621 (patch)
treeeb1899f86308c712e54ef94a1c85243c26621c45
parent46b6e2a34915a6d5cf7b1b15b3d2c28f54e02622 (diff)
downloadmu-3f34ac9369978b396d00a4fd02c9fb06b8eea621.tar.gz
4256 - get rid of container metadata entirely
We have some ugly duplication in computing size_of on containers between
layers 30/33 and 55.
-rw-r--r--030container.cc257
-rw-r--r--032array.cc80
-rw-r--r--033exclusive_container.cc35
-rw-r--r--035lookup.cc8
-rw-r--r--042name.cc2
-rw-r--r--055shape_shifting_container.cc140
6 files changed, 84 insertions, 438 deletions
diff --git a/030container.cc b/030container.cc
index 2ee8351d..f4aaafd4 100644
--- a/030container.cc
+++ b/030container.cc
@@ -13,8 +13,8 @@ get(Type, point).elements.push_back(reagent("y:number"));
 //: numbers, no matter how large they are.
 
 //: Tests in this layer often explicitly set up memory before reading it as a
-//: container. Don't do this in general. I'm tagging exceptions with /unsafe to
-//: skip later checks.
+//: container. Don't do this in general. I'm tagging such cases with /unsafe;
+//: they'll be exceptions to later checks.
 :(scenario copy_multiple_locations)
 def main [
   1:num <- copy 34
@@ -92,182 +92,28 @@ def main [
 ]
 +mem: storing 0 in location 7
 
-//: Can't put this in type_info because later layers will add support for more
-//: complex type trees where metadata depends on *combinations* of types.
-:(before "struct reagent")
-struct container_metadata {
-  int size;
-  vector<int> offset;  // not used by exclusive containers
-  // End container_metadata Fields
-  container_metadata() :size(0) {
-    // End container_metadata Constructor
-  }
-};
-:(before "End reagent Fields")
-container_metadata metadata;  // can't be a pointer into Container_metadata because we keep changing the base storage when we save/restore snapshots
-:(before "End reagent Copy Operator")
-metadata = other.metadata;
-:(before "End reagent Copy Constructor")
-metadata = other.metadata;
-
-:(before "End Globals")
-// todo: switch to map after figuring out how to consistently compare type trees
-vector<pair<type_tree*, container_metadata> > Container_metadata, Container_metadata_snapshot;
-:(before "End save_snapshots")
-Container_metadata_snapshot = Container_metadata;
-:(before "End restore_snapshots")
-restore_container_metadata();
-:(before "End One-time Setup")
-atexit(clear_container_metadata);
-:(code)
-// invariant: Container_metadata always contains a superset of Container_metadata_snapshot
-void restore_container_metadata() {
-  for (int i = 0;  i < SIZE(Container_metadata);  ++i) {
-    assert(Container_metadata.at(i).first);
-    if (i < SIZE(Container_metadata_snapshot)) {
-      assert(Container_metadata.at(i).first == Container_metadata_snapshot.at(i).first);
-      continue;
-    }
-    delete Container_metadata.at(i).first;
-    Container_metadata.at(i).first = NULL;
-  }
-  Container_metadata.resize(SIZE(Container_metadata_snapshot));
-}
-void clear_container_metadata() {
-  Container_metadata_snapshot.clear();
-  for (int i = 0;  i < SIZE(Container_metadata);  ++i) {
-    delete Container_metadata.at(i).first;
-    Container_metadata.at(i).first = NULL;
-  }
-  Container_metadata.clear();
-}
-
-//: do no work in size_of, simply lookup Container_metadata
-
-:(before "End size_of(reagent r) Special-cases")
-if (r.metadata.size) return r.metadata.size;
-
 :(before "End size_of(type) Special-cases")
-const type_tree* base_type = type;
-// Update base_type in size_of(type)
-if (!contains_key(Type, base_type->value)) {
-  raise << "no such type " << base_type->value << '\n' << end();
+if (type->value == -1) return 1;  // error value, but we'll raise it elsewhere
+if (type->value == 0) return 1;
+if (!contains_key(Type, type->value)) {
+  raise << "no such type " << type->value << '\n' << end();
   return 0;
 }
-type_info t = get(Type, base_type->value);
+type_info t = get(Type, type->value);
 if (t.kind == CONTAINER) {
-  // Compute size_of Container
-  if (!contains_key(Container_metadata, type)) {
-    raise << "unknown size for container type '" << to_string(type) << "'\n" << end();
-//?     DUMP("");
-    return 0;
-  }
-  return get(Container_metadata, type).size;
-}
-
-//: precompute Container_metadata before we need size_of
-//: also store a copy in each reagent in each instruction in each recipe
-
-:(after "End Type Modifying Transforms")
-Transform.push_back(compute_container_sizes);  // idempotent
-:(code)
-void compute_container_sizes(const recipe_ordinal r) {
-  recipe& caller = get(Recipe, r);
-  trace(9992, "transform") << "--- compute container sizes for " << caller.name << end();
-  for (int i = 0;  i < SIZE(caller.steps);  ++i) {
-    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), " in '"+to_original_string(inst)+"'");
-    for (int i = 0;  i < SIZE(inst.products);  ++i)
-      compute_container_sizes(inst.products.at(i), " in '"+to_original_string(inst)+"'");
-  }
-}
-
-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, 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, 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;
-  if (contains_key(pending_metadata, *type)) return;
-  pending_metadata.insert(*type);
-  if (!type->atom) {
-    if (!type->left->atom) {
-      raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end();
-      return;
+  // size of a container is the sum of the sizes of its elements
+  int result = 0;
+  for (int i = 0; i < SIZE(t.elements); ++i) {
+    // todo: strengthen assertion to disallow mutual type recursion
+    if (t.elements.at(i).type->value == type->value) {
+      raise << "container " << t.name << " can't include itself as a member\n" << end();
+      return 0;
     }
-    if (type->left->name == "address")
-      compute_container_sizes(payload_type(type), pending_metadata, location_for_error_messages);
-    // End compute_container_sizes Non-atom Special-cases
-    return;
+    result += size_of(element_type(type, i));
   }
-  assert(type->atom);
-  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, location_for_error_messages);
-  // End compute_container_sizes Atom Special-cases
-}
-
-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
-  // length in the type.)
-  container_metadata metadata;
-  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, location_for_error_messages);
-    metadata.offset.push_back(metadata.size);  // save previous size as offset
-    metadata.size += size_of(element.type);
-  }
-  Container_metadata.push_back(pair<type_tree*, container_metadata>(new type_tree(*full_type), metadata));
-}
-
-const type_tree* payload_type(const type_tree* type) {
-  assert(!type->atom);
-  const type_tree* result = type->right;
-  assert(!result->atom);
-  if (!result->right) return result->left;
   return result;
 }
 
-container_metadata& get(vector<pair<type_tree*, container_metadata> >& all, const type_tree* key) {
-  for (int i = 0;  i < SIZE(all);  ++i) {
-    if (matches(all.at(i).first, key))
-      return all.at(i).second;
-  }
-  raise << "unknown size for type '" << to_string(key) << "'\n" << end();
-  exit(1);
-}
-
-bool contains_key(const vector<pair<type_tree*, container_metadata> >& all, const type_tree* key) {
-  for (int i = 0;  i < SIZE(all);  ++i) {
-    if (matches(all.at(i).first, key))
-      return true;
-  }
-  return false;
-}
-
-bool matches(const type_tree* a, const type_tree* b) {
-  if (a == b) return true;
-  if (!a || !b) return false;
-  if (a->atom != b->atom) return false;
-  if (a->atom) return a->value == b->value;
-  return matches(a->left, b->left) && matches(a->right, b->right);
-}
-
 :(scenario stash_container)
 def main [
   1:num <- copy 34  # first
@@ -277,70 +123,6 @@ def main [
 ]
 +app: foo: 34 35 36
 
-//: for the following unit tests we'll do the work of the transform by hand
-
-:(before "End Unit Tests")
-void test_container_sizes() {
-  // a container we don't have the size for
-  reagent r("x:point");
-  CHECK(!contains_key(Container_metadata, r.type));
-  // scan
-  compute_container_sizes(r, "");
-  // the reagent we scanned knows its size
-  CHECK_EQ(r.metadata.size, 2);
-  // the global table also knows its size
-  CHECK(contains_key(Container_metadata, r.type));
-  CHECK_EQ(get(Container_metadata, r.type).size, 2);
-}
-
-void test_container_sizes_through_aliases() {
-  // a new alias for a container
-  put(Type_abbreviations, "pt", new_type_tree("point"));
-  reagent r("x:pt");
-  // scan
-  compute_container_sizes(r, "");
-  // the reagent we scanned knows its size
-  CHECK_EQ(r.metadata.size, 2);
-  // the global table also knows its size
-  CHECK(contains_key(Container_metadata, r.type));
-  CHECK_EQ(get(Container_metadata, r.type).size, 2);
-}
-
-void test_container_sizes_nested() {
-  // a container we don't have the size for
-  reagent r("x:point-number");
-  CHECK(!contains_key(Container_metadata, r.type));
-  // scan
-  compute_container_sizes(r, "");
-  // the reagent we scanned knows its size
-  CHECK_EQ(r.metadata.size, 3);
-  // the global table also knows its size
-  CHECK(contains_key(Container_metadata, r.type));
-  CHECK_EQ(get(Container_metadata, r.type).size, 3);
-}
-
-void test_container_sizes_recursive() {
-  // define a container containing an address to itself
-  run("container foo [\n"
-      "  x:num\n"
-      "  y:address:foo\n"
-      "]\n");
-  reagent r("x:foo");
-  compute_container_sizes(r, "");
-  CHECK_EQ(r.metadata.size, 2);
-}
-
-void test_container_sizes_from_address() {
-  // a container we don't have the size for
-  reagent container("x:point");
-  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, "");
-  CHECK(contains_key(Container_metadata, container.type));
-  CHECK_EQ(get(Container_metadata, container.type).size, 2);
-}
-
 //:: To access elements of a container, use 'get'
 //: 'get' takes a 'base' container and an 'offset' into it and returns the
 //: appropriate element of the container value.
@@ -413,8 +195,9 @@ case GET: {
   // Update GET base_type in Run
   int offset = ingredients.at(1).at(0);
   if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break;  // copied from Check above
-  assert(base.metadata.size);
-  int src = base_address + base.metadata.offset.at(offset);
+  int src = base_address;
+  for (int i = 0; i < offset; ++i)
+    src += size_of(element_type(base.type, i));
   trace(9998, "run") << "address to copy is " << src << end();
   //: use base.type rather than base_type because later layers will introduce compound types
   reagent/*copy*/ element = element_type(base.type, offset);
@@ -569,7 +352,9 @@ case PUT: {
   // Update PUT base_type in Run
   int offset = ingredients.at(1).at(0);
   if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break;  // copied from Check above
-  int address = base_address + base.metadata.offset.at(offset);
+  int address = base_address;
+  for (int i = 0; i < offset; ++i)
+    address += size_of(element_type(base.type, i));
   trace(9998, "run") << "address to copy to is " << address << end();
   // optimization: directly write the element rather than updating 'product'
   // and writing the entire container
diff --git a/032array.cc b/032array.cc
index a696b450..3bde42fb 100644
--- a/032array.cc
+++ b/032array.cc
@@ -200,86 +200,6 @@ def foo [
 ]
 # shouldn't die
 
-//:: containers inside arrays
-//: make sure we compute container sizes inside arrays
-
-:(before "End compute_container_sizes Non-atom Special-cases")
-else if (type->left->name == "array")
-  compute_container_sizes(array_element(type), pending_metadata, location_for_error_messages);
-
-:(before "End Unit Tests")
-void test_container_sizes_from_array() {
-  // a container we don't have the size for
-  reagent container("x:point");
-  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, "");
-  CHECK(contains_key(Container_metadata, container.type));
-  CHECK_EQ(get(Container_metadata, container.type).size, 2);
-}
-
-void test_container_sizes_from_address_to_array() {
-  // a container we don't have the size for
-  reagent container("x:point");
-  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, "");
-  CHECK(contains_key(Container_metadata, container.type));
-  CHECK_EQ(get(Container_metadata, container.type).size, 2);
-}
-
-void test_container_sizes_from_static_array() {
-  // a container we don't have the size for
-  reagent container("x:point");
-  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, "");
-  CHECK(contains_key(Container_metadata, container.type));
-  CHECK_EQ(get(Container_metadata, container.type).size, 2);
-  // no non-container types precomputed
-  CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
-}
-
-void test_container_sizes_from_address_to_static_array() {
-  // a container we don't have the size for
-  reagent container("x:point");
-  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, "");
-  CHECK(contains_key(Container_metadata, container.type));
-  CHECK_EQ(get(Container_metadata, container.type).size, 2);
-  // no non-container types precomputed
-  CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
-}
-
-void test_container_sizes_from_repeated_address_and_array_types() {
-  // a container we don't have the size for
-  reagent container("x:point");
-  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, "");
-  CHECK(contains_key(Container_metadata, container.type));
-  CHECK_EQ(get(Container_metadata, container.type).size, 2);
-  // no non-container types precomputed
-  CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
-}
-
-void test_container_sizes_on_unknown_type() {
-  // a container we don't have the size for
-  reagent container("x:point");
-  int old_size = SIZE(Container_metadata);
-  // scanning address to array with a typo
-  reagent r("x:address:array:adress:number");
-  compute_container_sizes(r, "");  // should not crash
-  // no non-container types precomputed
-  CHECK_EQ(SIZE(Container_metadata), old_size);
-}
-
 //:: To access elements of an array, use 'index'
 
 :(scenario index)
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index 29a524c9..44161d7c 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -15,9 +15,9 @@ get(Type, tmp).elements.push_back(reagent("i:number"));
 get(Type, tmp).elements.push_back(reagent("p:point"));
 }
 
-//: Tests in this layer often explicitly set up memory before reading it as an
-//: array. Don't do this in general. I'm tagging exceptions with /raw to keep
-//: checks in future layers from flagging them.
+//: Tests in this layer often explicitly set up memory before reading it as a
+//: container. Don't do this in general. I'm tagging such cases with /unsafe;
+//: they'll be exceptions to later checks.
 :(scenario copy_exclusive_container)
 # Copying exclusive containers copies all their contents and an extra location for the tag.
 def main [
@@ -32,30 +32,17 @@ def main [
 
 :(before "End size_of(type) Special-cases")
 if (t.kind == EXCLUSIVE_CONTAINER) {
-  // Compute size_of Exclusive Container
-  return get(Container_metadata, type).size;
-}
-:(before "End compute_container_sizes Atom Special-cases")
-if (info.kind == EXCLUSIVE_CONTAINER) {
-  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, 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.)
-  container_metadata metadata;
-  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, location_for_error_messages);
-    int variant_size = size_of(element);
-    if (variant_size > metadata.size) metadata.size = variant_size;
+  // (So like containers, it can't contain arrays.)
+  int result = 0;
+  for (int i = 0; i < SIZE(t.elements); ++i) {
+    reagent tmp;
+    tmp.type = new type_tree(*type);
+    int size = size_of(variant_type(tmp, i));
+    if (size > result) result = size;
   }
   // ...+1 for its tag.
-  ++metadata.size;
-  Container_metadata.push_back(pair<type_tree*, container_metadata>(new type_tree(*full_type), metadata));
+  return result+1;
 }
 
 //:: To access variants of an exclusive container, use 'maybe-convert'.
diff --git a/035lookup.cc b/035lookup.cc
index 1823ae3d..a2647f5d 100644
--- a/035lookup.cc
+++ b/035lookup.cc
@@ -127,14 +127,6 @@ canonize_type(product);
 canonize_type(lhs);
 canonize_type(rhs);
 
-:(before "Compute Container Size(reagent rcopy)")
-if (!canonize_type(rcopy)) return;
-
-:(before "Compute Container Size(element, full_type)")
-assert(!has_property(element, "lookup"));
-:(before "Compute Exclusive Container Size(element, full_type)")
-assert(!has_property(element, "lookup"));
-
 :(code)
 bool canonize_type(reagent& r) {
   while (has_property(r, "lookup")) {
diff --git a/042name.cc b/042name.cc
index 077eed0d..f183962c 100644
--- a/042name.cc
+++ b/042name.cc
@@ -18,7 +18,7 @@ def main [
 +error: main: tried to read ingredient 'y' in 'x:num <- copy y:num' but it hasn't been written to yet
 # todo: detect conditional defines
 
-:(after "Transform.push_back(compute_container_sizes)")
+:(after "End Type Modifying Transforms")
 Transform.push_back(transform_names);  // idempotent
 
 :(before "End Globals")
diff --git a/055shape_shifting_container.cc b/055shape_shifting_container.cc
index 32032456..0e7409d8 100644
--- a/055shape_shifting_container.cc
+++ b/055shape_shifting_container.cc
@@ -12,16 +12,8 @@ base_type = get_base_type(base_type);
 base_type = get_base_type(base_type);
 :(after "Update MAYBE_CONVERT base_type in Check")
 base_type = get_base_type(base_type);
-:(after "Update base_type in size_of(type)")
-base_type = get_base_type(base_type);
 :(after "Update base_type in element_type")
 base_type = get_base_type(base_type);
-//? :(after "Update base_type in compute_container_address_offsets")
-//? base_type = get_base_type(base_type);
-//? :(after "Update base_type in append_container_address_offsets")
-//? base_type = get_base_type(base_type);
-//? :(after "Update element_base_type For Exclusive Container in append_addresses")
-//? element_base_type = get_base_type(element_base_type);
 :(after "Update base_type in skip_addresses")
 base_type = get_base_type(base_type);
 :(replace{} "const type_tree* get_base_type(const type_tree* t)")
@@ -39,6 +31,8 @@ def main [
 ]
 # no crash
 
+//: update size_of to handle non-atom container types
+
 :(scenario size_of_shape_shifting_container)
 container foo:_t [
   x:_t
@@ -310,18 +304,53 @@ def main [
 
 :(before "End element_type Special-cases")
 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, location_for_error_messages);
-:(before "Compute Exclusive Container Size(element, full_type)")
-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, location_for_error_messages);
-//? if (contains_type_ingredient(element)) return;  // error raised elsewhere
-
-:(after "Compute size_of Container")
-assert(!contains_type_ingredient(type));
-:(after "Compute size_of Exclusive Container")
-assert(!contains_type_ingredient(type));
+
+:(before "End size_of(type) Non-atom Special-cases")
+assert(type->left->atom);
+if (!contains_key(Type, type->left->value)) {
+  raise << "no such type " << type->left->value << '\n' << end();
+  return 0;
+}
+type_info t = get(Type, type->left->value);
+if (t.kind == CONTAINER) {
+  // size of a container is the sum of the sizes of its elements
+  int result = 0;
+  for (int i = 0; i < SIZE(t.elements); ++i) {
+    // todo: strengthen assertion to disallow mutual type recursion
+    if (get_base_type(t.elements.at(i).type)->value == get_base_type(type)->value) {
+      raise << "container " << t.name << " can't include itself as a member\n" << end();
+      return 0;
+    }
+    result += size_of(element_type(type, i));
+  }
+  return result;
+}
+if (t.kind == EXCLUSIVE_CONTAINER) {
+  // size of an exclusive container is the size of its largest variant
+  // (So like containers, it can't contain arrays.)
+  int result = 0;
+  for (int i = 0; i < SIZE(t.elements); ++i) {
+    reagent tmp;
+    tmp.type = new type_tree(*type);
+    int size = size_of(variant_type(tmp, i));
+    if (size > result) result = size;
+  }
+  // ...+1 for its tag.
+  return result+1;
+}
+
+:(scenario complex_shape_shifting_exclusive_container)
+exclusive-container foo:_a [
+  x:_a
+  y:num
+]
+def main [
+  1:text <- new [abc]
+  2:foo:point <- merge 0/variant, 34/xx, 35/xy
+  10:point, 20:bool <- maybe-convert 2:foo:point, 0/variant
+]
++mem: storing 1 in location 20
++mem: storing 35 in location 11
 
 :(code)
 bool contains_type_ingredient(const reagent& x) {
@@ -539,75 +568,8 @@ 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 in '1:num <- get 10:foo, 1:offset'
-
-//:: fix up previous layers
-
-//: We have two transforms in previous layers -- for computing sizes and
-//: offsets containing addresses for containers and exclusive containers --
-//: that we need to teach about type ingredients.
-
-:(before "End compute_container_sizes Non-atom Special-cases")
-const type_tree* root = get_base_type(type);
-if (contains_key(Type, root->value)) {
-  type_info& info = get(Type, root->value);
-  if (info.kind == CONTAINER) {
-    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, location_for_error_messages);
-    return;
-  }
-}  // otherwise error raised elsewhere
-
-:(before "End Unit Tests")
-void test_container_sizes_shape_shifting_container() {
-  run("container foo:_t [\n"
-      "  x:num\n"
-      "  y:_t\n"
-      "]\n");
-  reagent r("x:foo:point");
-  compute_container_sizes(r, "");
-  CHECK_EQ(r.metadata.size, 3);
-}
-
-void test_container_sizes_shape_shifting_exclusive_container() {
-  run("exclusive-container foo:_t [\n"
-      "  x:num\n"
-      "  y:_t\n"
-      "]\n");
-  reagent r("x:foo:point");
-  compute_container_sizes(r, "");
-  CHECK_EQ(r.metadata.size, 3);
-  reagent r2("x:foo:num");
-  compute_container_sizes(r2, "");
-  CHECK_EQ(r2.metadata.size, 2);
-}
-
-void test_container_sizes_compound_type_ingredient() {
-  run("container foo:_t [\n"
-      "  x:num\n"
-      "  y:_t\n"
-      "]\n");
-  reagent r("x:foo:&:point");
-  compute_container_sizes(r, "");
-  CHECK_EQ(r.metadata.size, 2);
-  // scan also pre-computes metadata for type ingredient
-  reagent point("x:point");
-  CHECK(contains_key(Container_metadata, point.type));
-  CHECK_EQ(get(Container_metadata, point.type).size, 2);
-}
-
-void test_container_sizes_recursive_shape_shifting_container() {
-  run("container foo:_t [\n"
-      "  x:num\n"
-      "  y:&:foo:_t\n"
-      "]\n");
-  reagent r2("x:foo:num");
-  compute_container_sizes(r2, "");
-  CHECK_EQ(r2.metadata.size, 2);
-}
+# todo: improve error message
++error: illegal type "foo" seems to be missing a type ingredient or three while computing element type of container
 
 :(scenario typos_in_container_definitions)
 % Hide_errors = true;