about summary refs log tree commit diff stats
path: root/html/059shape_shifting_recipe.cc.html
diff options
context:
space:
mode:
Diffstat (limited to 'html/059shape_shifting_recipe.cc.html')
-rw-r--r--html/059shape_shifting_recipe.cc.html252
1 files changed, 230 insertions, 22 deletions
diff --git a/html/059shape_shifting_recipe.cc.html b/html/059shape_shifting_recipe.cc.html
index 2df37fa3..13c436c4 100644
--- a/html/059shape_shifting_recipe.cc.html
+++ b/html/059shape_shifting_recipe.cc.html
@@ -16,6 +16,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; }
 .traceContains { color: #008000; }
 .Special { color: #ff6060; }
 .cSpecial { color: #008000; }
+.CommentedCode { color: #6c6c6c; }
 .Comment { color: #9090ff; }
 .Delimiter { color: #a04060; }
 .SalientComment { color: #00ffff; }
@@ -54,11 +55,26 @@ recipe foo a:_t <span class="Delimiter">-&gt;</span> result:_t [
 <span class="traceContains">+mem: storing 14 in location 11</span>
 <span class="traceContains">+mem: storing 15 in location 12</span>
 
-<span class="Comment">//: Before anything else, disable transforms for shape-shifting recipes.</span>
+<span class="Comment">//: Before anything else, disable transforms for shape-shifting recipes and</span>
+<span class="Comment">//: make sure we never try to actually run a shape-shifting recipe. We should</span>
+<span class="Comment">//: be rewriting such instructions to *specializations* with the type</span>
+<span class="Comment">//: ingredients filled in.</span>
 
 <span class="Delimiter">:(before &quot;End Transform Checks&quot;)</span>
 if <span class="Delimiter">(</span>any_type_ingredient_in_header<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">recipe_ordinal</span><span class="Comment">*/</span>p<span class="Delimiter">-&gt;</span>first<span class="Delimiter">))</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
 
+<span class="Delimiter">:(after &quot;Running One Instruction&quot;)</span>
+if <span class="Delimiter">(</span>Current_routine<span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>front<span class="Delimiter">().</span>running_step_index == <span class="Constant">0</span>
+    &amp;&amp; any_type_ingredient_in_header<span class="Delimiter">(</span>Current_routine<span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>front<span class="Delimiter">().</span>running_recipe<span class="Delimiter">))</span> <span class="Delimiter">{</span>
+<span class="CommentedCode">//?   DUMP(&quot;&quot;);</span>
+  raise_error &lt;&lt; <span class="Constant">&quot;ran into unspecialized shape-shifting recipe &quot;</span> &lt;&lt; current_recipe_name<span class="Delimiter">()</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
+<span class="Delimiter">}</span>
+
+<span class="Comment">//: Make sure we don't match up literals with type ingredients without</span>
+<span class="Comment">//: specialization.</span>
+<span class="Delimiter">:(before &quot;End valid_type_for_literal Special-cases&quot;)</span>
+if <span class="Delimiter">(</span>contains_type_ingredient_name<span class="Delimiter">(</span>lhs<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
+
 <span class="Comment">//: We'll be creating recipes without loading them from anywhere by</span>
 <span class="Comment">//: *specializing* existing recipes, so make sure we don't clear any of those</span>
 <span class="Comment">//: when we start running tests.</span>
@@ -68,24 +84,35 @@ recently_added_types<span class="Delimiter">.</span>clear<span class="Delimiter"
 
 <span class="Delimiter">:(before &quot;End Instruction Dispatch(inst, best_score)&quot;)</span>
 if <span class="Delimiter">(</span>best_score == -<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
+<span class="CommentedCode">//?   if (inst.name == &quot;push-duplex&quot;) Trace_stream = new trace_stream;</span>
   trace<span class="Delimiter">(</span><span class="Constant">9992</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;no variant found; searching for variant with suitable type ingredients&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
   recipe_ordinal exemplar = pick_matching_shape_shifting_variant<span class="Delimiter">(</span>variants<span class="Delimiter">,</span> inst<span class="Delimiter">,</span> best_score<span class="Delimiter">);</span>
   if <span class="Delimiter">(</span>exemplar<span class="Delimiter">)</span> <span class="Delimiter">{</span>
     trace<span class="Delimiter">(</span><span class="Constant">9992</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;found variant to specialize: &quot;</span> &lt;&lt; exemplar &lt;&lt; <span class="Constant">' '</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> exemplar<span class="Delimiter">).</span>name &lt;&lt; end<span class="Delimiter">();</span>
     variants<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>new_variant<span class="Delimiter">(</span>exemplar<span class="Delimiter">,</span> inst<span class="Delimiter">,</span> caller_recipe<span class="Delimiter">));</span>
+<span class="CommentedCode">//?     cerr &lt;&lt; &quot;-- replacing &quot; &lt;&lt; inst.name &lt;&lt; &quot; with &quot; &lt;&lt; get(Recipe, variants.back()).name &lt;&lt; '\n' &lt;&lt; debug_string(get(Recipe, variants.back()));</span>
     inst<span class="Delimiter">.</span>name = get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> variants<span class="Delimiter">.</span>back<span class="Delimiter">()).</span>name<span class="Delimiter">;</span>
     trace<span class="Delimiter">(</span><span class="Constant">9992</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;new specialization: &quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>name &lt;&lt; end<span class="Delimiter">();</span>
   <span class="Delimiter">}</span>
+<span class="CommentedCode">//?   if (inst.name == &quot;push-duplex&quot;) {</span>
+<span class="CommentedCode">//?     cerr &lt;&lt; &quot;======== {\n&quot;;</span>
+<span class="CommentedCode">//?     cerr &lt;&lt; inst.to_string() &lt;&lt; '\n';</span>
+<span class="CommentedCode">//?     DUMP(&quot;&quot;);</span>
+<span class="CommentedCode">//?     cerr &lt;&lt; &quot;======== }\n&quot;;</span>
+<span class="CommentedCode">//?   }</span>
 <span class="Delimiter">}</span>
 
 <span class="Delimiter">:(code)</span>
 recipe_ordinal pick_matching_shape_shifting_variant<span class="Delimiter">(</span>vector&lt;recipe_ordinal&gt;&amp; variants<span class="Delimiter">,</span> const instruction&amp; inst<span class="Delimiter">,</span> long long int&amp; best_score<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+<span class="CommentedCode">//?   cerr &lt;&lt; &quot;---- &quot; &lt;&lt; inst.name &lt;&lt; &quot;: &quot; &lt;&lt; non_ghost_size(variants) &lt;&lt; '\n';</span>
   recipe_ordinal result = <span class="Constant">0</span><span class="Delimiter">;</span>
   for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>variants<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
     if <span class="Delimiter">(</span>variants<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)</span> == -<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>  <span class="Comment">// ghost from a previous test</span>
+<span class="CommentedCode">//?     cerr &lt;&lt; &quot;-- variant &quot; &lt;&lt; i &lt;&lt; &quot;\n&quot; &lt;&lt; debug_string(get(Recipe, variants.at(i)));</span>
     trace<span class="Delimiter">(</span><span class="Constant">9992</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;checking shape-shifting variant &quot;</span> &lt;&lt; i &lt;&lt; end<span class="Delimiter">();</span>
     long long int current_score = shape_shifting_variant_score<span class="Delimiter">(</span>inst<span class="Delimiter">,</span> variants<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span>
     trace<span class="Delimiter">(</span><span class="Constant">9992</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;final score: &quot;</span> &lt;&lt; current_score &lt;&lt; end<span class="Delimiter">();</span>
+<span class="CommentedCode">//?     cerr &lt;&lt; get(Recipe, variants.at(i)).name &lt;&lt; &quot;: &quot; &lt;&lt; current_score &lt;&lt; '\n';</span>
     if <span class="Delimiter">(</span>current_score &gt; best_score<span class="Delimiter">)</span> <span class="Delimiter">{</span>
       trace<span class="Delimiter">(</span><span class="Constant">9992</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;matches&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
       result = variants<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
@@ -96,6 +123,7 @@ recipe_ordinal pick_matching_shape_shifting_variant<span class="Delimiter">(</sp
 <span class="Delimiter">}</span>
 
 long long int shape_shifting_variant_score<span class="Delimiter">(</span>const instruction&amp; inst<span class="Delimiter">,</span> recipe_ordinal variant<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+<span class="CommentedCode">//?   cerr &lt;&lt; &quot;======== &quot; &lt;&lt; inst.to_string() &lt;&lt; '\n';</span>
   if <span class="Delimiter">(</span>!any_type_ingredient_in_header<span class="Delimiter">(</span>variant<span class="Delimiter">))</span> <span class="Delimiter">{</span>
     trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;no type ingredients&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">return</span> -<span class="Constant">1</span><span class="Delimiter">;</span>
@@ -106,7 +134,7 @@ long long int shape_shifting_variant_score<span class="Delimiter">(</span>const
     <span class="Identifier">return</span> -<span class="Constant">1</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
   for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>header_ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    if <span class="Delimiter">(</span>!non_type_ingredients_match<span class="Delimiter">(</span>header_ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">),</span> inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)))</span> <span class="Delimiter">{</span>
+    if <span class="Delimiter">(</span>!deeply_equal_concrete_types<span class="Delimiter">(</span>header_ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">),</span> inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)))</span> <span class="Delimiter">{</span>
       trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;mismatch: ingredient &quot;</span> &lt;&lt; i &lt;&lt; end<span class="Delimiter">();</span>
       <span class="Identifier">return</span> -<span class="Constant">1</span><span class="Delimiter">;</span>
     <span class="Delimiter">}</span>
@@ -117,7 +145,7 @@ long long int shape_shifting_variant_score<span class="Delimiter">(</span>const
   <span class="Delimiter">}</span>
   const vector&lt;reagent&gt;&amp; header_products = get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> variant<span class="Delimiter">).</span>products<span class="Delimiter">;</span>
   for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    if <span class="Delimiter">(</span>!non_type_ingredients_match<span class="Delimiter">(</span>header_products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">),</span> inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)))</span> <span class="Delimiter">{</span>
+    if <span class="Delimiter">(</span>!deeply_equal_concrete_types<span class="Delimiter">(</span>header_products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">),</span> inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)))</span> <span class="Delimiter">{</span>
       trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;mismatch: product &quot;</span> &lt;&lt; i &lt;&lt; end<span class="Delimiter">();</span>
       <span class="Identifier">return</span> -<span class="Constant">1</span><span class="Delimiter">;</span>
     <span class="Delimiter">}</span>
@@ -139,9 +167,29 @@ bool any_type_ingredient_in_header<span class="Delimiter">(</span>recipe_ordinal
   <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
 <span class="Delimiter">}</span>
 
-bool non_type_ingredients_match<span class="Delimiter">(</span>const reagent&amp; lhs<span class="Delimiter">,</span> const reagent&amp; rhs<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-  if <span class="Delimiter">(</span>contains_type_ingredient_name<span class="Delimiter">(</span>lhs<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span>
-  <span class="Identifier">return</span> types_match<span class="Delimiter">(</span>lhs<span class="Delimiter">,</span> rhs<span class="Delimiter">);</span>
+bool deeply_equal_concrete_types<span class="Delimiter">(</span>reagent lhs<span class="Delimiter">,</span> reagent rhs<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+<span class="CommentedCode">//?   cerr &lt;&lt; debug_string(lhs) &lt;&lt; &quot; vs &quot; &lt;&lt; debug_string(rhs) &lt;&lt; '\n';</span>
+<span class="CommentedCode">//?   bool result = deeply_equal_concrete_types(lhs.properties.at(0).second, rhs.properties.at(0).second, rhs);</span>
+<span class="CommentedCode">//?   cerr &lt;&lt; &quot;  =&gt; &quot; &lt;&lt; result &lt;&lt; '\n';</span>
+<span class="CommentedCode">//?   return result;</span>
+<span class="CommentedCode">//?   cerr &lt;&lt; &quot;== &quot; &lt;&lt; debug_string(lhs) &lt;&lt; &quot; vs &quot; &lt;&lt; debug_string(rhs) &lt;&lt; '\n';</span>
+  canonize_type<span class="Delimiter">(</span>lhs<span class="Delimiter">);</span>
+  canonize_type<span class="Delimiter">(</span>rhs<span class="Delimiter">);</span>
+  <span class="Identifier">return</span> deeply_equal_concrete_types<span class="Delimiter">(</span>lhs<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>second<span class="Delimiter">,</span> rhs<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>second<span class="Delimiter">,</span> rhs<span class="Delimiter">);</span>
+<span class="Delimiter">}</span>
+
+bool deeply_equal_concrete_types<span class="Delimiter">(</span>const string_tree* lhs<span class="Delimiter">,</span> const string_tree* rhs<span class="Delimiter">,</span> const reagent&amp; rhs_reagent<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  if <span class="Delimiter">(</span>!lhs<span class="Delimiter">)</span> <span class="Identifier">return</span> !rhs<span class="Delimiter">;</span>
+  if <span class="Delimiter">(</span>!rhs<span class="Delimiter">)</span> <span class="Identifier">return</span> !lhs<span class="Delimiter">;</span>
+  if <span class="Delimiter">(</span>is_type_ingredient_name<span class="Delimiter">(</span>lhs<span class="Delimiter">-&gt;</span>value<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span>  <span class="Comment">// type ingredient matches anything</span>
+  if <span class="Delimiter">(</span>Literal_type_names<span class="Delimiter">.</span>find<span class="Delimiter">(</span>lhs<span class="Delimiter">-&gt;</span>value<span class="Delimiter">)</span> != Literal_type_names<span class="Delimiter">.</span>end<span class="Delimiter">())</span>
+    <span class="Identifier">return</span> Literal_type_names<span class="Delimiter">.</span>find<span class="Delimiter">(</span>rhs<span class="Delimiter">-&gt;</span>value<span class="Delimiter">)</span> != Literal_type_names<span class="Delimiter">.</span>end<span class="Delimiter">();</span>
+  if <span class="Delimiter">(</span>rhs<span class="Delimiter">-&gt;</span>value == <span class="Constant">&quot;literal&quot;</span> &amp;&amp; lhs<span class="Delimiter">-&gt;</span>value == <span class="Constant">&quot;address&quot;</span><span class="Delimiter">)</span>
+    <span class="Identifier">return</span> rhs_reagent<span class="Delimiter">.</span>name == <span class="Constant">&quot;0&quot;</span><span class="Delimiter">;</span>
+<span class="CommentedCode">//?   cerr &lt;&lt; lhs-&gt;value &lt;&lt; &quot; vs &quot; &lt;&lt; rhs-&gt;value &lt;&lt; '\n';</span>
+  <span class="Identifier">return</span> lhs<span class="Delimiter">-&gt;</span>value == rhs<span class="Delimiter">-&gt;</span>value
+      &amp;&amp; deeply_equal_concrete_types<span class="Delimiter">(</span>lhs<span class="Delimiter">-&gt;</span>left<span class="Delimiter">,</span> rhs<span class="Delimiter">-&gt;</span>left<span class="Delimiter">,</span> rhs_reagent<span class="Delimiter">)</span>
+      &amp;&amp; deeply_equal_concrete_types<span class="Delimiter">(</span>lhs<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> rhs<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> rhs_reagent<span class="Delimiter">);</span>
 <span class="Delimiter">}</span>
 
 bool contains_type_ingredient_name<span class="Delimiter">(</span>const reagent&amp; x<span class="Delimiter">)</span> <span class="Delimiter">{</span>
@@ -183,7 +231,7 @@ recipe_ordinal new_variant<span class="Delimiter">(</span>recipe_ordinal exempla
       delete p<span class="Delimiter">-&gt;</span>second<span class="Delimiter">;</span>
     if <span class="Delimiter">(</span>error<span class="Delimiter">)</span> <span class="Identifier">return</span> exemplar<span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
-  ensure_all_concrete_types<span class="Delimiter">(</span>new_recipe<span class="Delimiter">);</span>
+  ensure_all_concrete_types<span class="Delimiter">(</span>new_recipe<span class="Delimiter">,</span> get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> exemplar<span class="Delimiter">));</span>
   <span class="Comment">// finally, perform all transforms on the new specialization</span>
   for <span class="Delimiter">(</span>long long int t = <span class="Constant">0</span><span class="Delimiter">;</span> t &lt; SIZE<span class="Delimiter">(</span>Transform<span class="Delimiter">);</span> ++t<span class="Delimiter">)</span> <span class="Delimiter">{</span>
     <span class="Delimiter">(</span>*Transform<span class="Delimiter">.</span>at<span class="Delimiter">(</span>t<span class="Delimiter">))(</span>new_recipe_ordinal<span class="Delimiter">);</span>
@@ -227,14 +275,17 @@ void save_or_deduce_type_name<span class="Delimiter">(</span>reagent&amp; x<span
 <span class="Delimiter">}</span>
 
 void compute_type_ingredient_mappings<span class="Delimiter">(</span>const recipe&amp; exemplar<span class="Delimiter">,</span> const instruction&amp; inst<span class="Delimiter">,</span> map&lt;string<span class="Delimiter">,</span> const string_tree*&gt;&amp; mappings<span class="Delimiter">,</span> const recipe&amp; caller_recipe<span class="Delimiter">,</span> bool* error<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-  for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>exemplar<span class="Delimiter">.</span>ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  long long int limit = min<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">),</span> SIZE<span class="Delimiter">(</span>exemplar<span class="Delimiter">.</span>ingredients<span class="Delimiter">));</span>
+  for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; limit<span class="Delimiter">;</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
     const reagent&amp; exemplar_reagent = exemplar<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
     reagent ingredient = inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
     assert<span class="Delimiter">(</span>ingredient<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>second<span class="Delimiter">);</span>
     canonize_type<span class="Delimiter">(</span>ingredient<span class="Delimiter">);</span>
+    if <span class="Delimiter">(</span>is_mu_address<span class="Delimiter">(</span>exemplar_reagent<span class="Delimiter">)</span> &amp;&amp; ingredient<span class="Delimiter">.</span>name == <span class="Constant">&quot;0&quot;</span><span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>  <span class="Comment">// assume it matches</span>
     accumulate_type_ingredients<span class="Delimiter">(</span>exemplar_reagent<span class="Delimiter">,</span> ingredient<span class="Delimiter">,</span> mappings<span class="Delimiter">,</span> exemplar<span class="Delimiter">,</span> inst<span class="Delimiter">,</span> caller_recipe<span class="Delimiter">,</span> error<span class="Delimiter">);</span>
   <span class="Delimiter">}</span>
-  for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>exemplar<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  limit = min<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">),</span> SIZE<span class="Delimiter">(</span>exemplar<span class="Delimiter">.</span>products<span class="Delimiter">));</span>
+  for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; limit<span class="Delimiter">;</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
     const reagent&amp; exemplar_reagent = exemplar<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
     reagent product = inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
     assert<span class="Delimiter">(</span>product<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>second<span class="Delimiter">);</span>
@@ -243,6 +294,10 @@ void compute_type_ingredient_mappings<span class="Delimiter">(</span>const recip
   <span class="Delimiter">}</span>
 <span class="Delimiter">}</span>
 
+inline long long int min<span class="Delimiter">(</span>long long int a<span class="Delimiter">,</span> long long int b<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  <span class="Identifier">return</span> <span class="Delimiter">(</span>a &lt; b<span class="Delimiter">)</span> ? a : b<span class="Delimiter">;</span>
+<span class="Delimiter">}</span>
+
 void accumulate_type_ingredients<span class="Delimiter">(</span>const reagent&amp; exemplar_reagent<span class="Delimiter">,</span> reagent&amp; refinement<span class="Delimiter">,</span> map&lt;string<span class="Delimiter">,</span> const string_tree*&gt;&amp; mappings<span class="Delimiter">,</span> const recipe&amp; exemplar<span class="Delimiter">,</span> const instruction&amp; call_instruction<span class="Delimiter">,</span> const recipe&amp; caller_recipe<span class="Delimiter">,</span> bool* error<span class="Delimiter">)</span> <span class="Delimiter">{</span>
   assert<span class="Delimiter">(</span>refinement<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>second<span class="Delimiter">);</span>
   accumulate_type_ingredients<span class="Delimiter">(</span>exemplar_reagent<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>second<span class="Delimiter">,</span> refinement<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>second<span class="Delimiter">,</span> mappings<span class="Delimiter">,</span> exemplar<span class="Delimiter">,</span> exemplar_reagent<span class="Delimiter">,</span> call_instruction<span class="Delimiter">,</span> caller_recipe<span class="Delimiter">,</span> error<span class="Delimiter">);</span>
@@ -262,11 +317,15 @@ void accumulate_type_ingredients<span class="Delimiter">(</span>const string_tre
     <span class="Delimiter">}</span>
     if <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>mappings<span class="Delimiter">,</span> exemplar_type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">))</span> <span class="Delimiter">{</span>
       trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;adding mapping from &quot;</span> &lt;&lt; exemplar_type<span class="Delimiter">-&gt;</span>value &lt;&lt; <span class="Constant">&quot; to &quot;</span> &lt;&lt; debug_string<span class="Delimiter">(</span>refinement_type<span class="Delimiter">)</span> &lt;&lt; end<span class="Delimiter">();</span>
-      put<span class="Delimiter">(</span>mappings<span class="Delimiter">,</span> exemplar_type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">,</span> new string_tree<span class="Delimiter">(</span>*refinement_type<span class="Delimiter">));</span>
+      if <span class="Delimiter">(</span>refinement_type<span class="Delimiter">-&gt;</span>value == <span class="Constant">&quot;literal&quot;</span><span class="Delimiter">)</span>
+        put<span class="Delimiter">(</span>mappings<span class="Delimiter">,</span> exemplar_type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">,</span> new string_tree<span class="Delimiter">(</span><span class="Constant">&quot;number&quot;</span><span class="Delimiter">));</span>
+      else
+        put<span class="Delimiter">(</span>mappings<span class="Delimiter">,</span> exemplar_type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">,</span> new string_tree<span class="Delimiter">(</span>*refinement_type<span class="Delimiter">));</span>
     <span class="Delimiter">}</span>
     else <span class="Delimiter">{</span>
-      if <span class="Delimiter">(</span>!deeply_equal<span class="Delimiter">(</span>get<span class="Delimiter">(</span>mappings<span class="Delimiter">,</span> exemplar_type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">),</span> refinement_type<span class="Delimiter">))</span> <span class="Delimiter">{</span>
+      if <span class="Delimiter">(</span>!deeply_equal_types<span class="Delimiter">(</span>get<span class="Delimiter">(</span>mappings<span class="Delimiter">,</span> exemplar_type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">),</span> refinement_type<span class="Delimiter">))</span> <span class="Delimiter">{</span>
         raise_error &lt;&lt; maybe<span class="Delimiter">(</span>caller_recipe<span class="Delimiter">.</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;no call found for '&quot;</span> &lt;&lt; call_instruction<span class="Delimiter">.</span>to_string<span class="Delimiter">()</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
+<span class="CommentedCode">//?         cerr &lt;&lt; exemplar_type-&gt;value &lt;&lt; &quot;: &quot; &lt;&lt; debug_string(get(mappings, exemplar_type-&gt;value)) &lt;&lt; &quot; vs &quot; &lt;&lt; debug_string(refinement_type) &lt;&lt; '\n';</span>
         *error = <span class="Constant">true</span><span class="Delimiter">;</span>
         <span class="Identifier">return</span><span class="Delimiter">;</span>
       <span class="Delimiter">}</span>
@@ -330,31 +389,39 @@ void replace_type_ingredients<span class="Delimiter">(</span>string_tree* type<s
   replace_type_ingredients<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> mappings<span class="Delimiter">);</span>
 <span class="Delimiter">}</span>
 
-void ensure_all_concrete_types<span class="Delimiter">(</span>const recipe&amp; new_recipe<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+void ensure_all_concrete_types<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">const</span><span class="Comment">*/</span> recipe&amp; new_recipe<span class="Delimiter">,</span> const recipe&amp; exemplar<span class="Delimiter">)</span> <span class="Delimiter">{</span>
   for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>new_recipe<span class="Delimiter">.</span>ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
-    ensure_all_concrete_types<span class="Delimiter">(</span>new_recipe<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>type<span class="Delimiter">);</span>
+    ensure_all_concrete_types<span class="Delimiter">(</span>new_recipe<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">),</span> exemplar<span class="Delimiter">);</span>
   for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>new_recipe<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
-    ensure_all_concrete_types<span class="Delimiter">(</span>new_recipe<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>type<span class="Delimiter">);</span>
+    ensure_all_concrete_types<span class="Delimiter">(</span>new_recipe<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">),</span> exemplar<span class="Delimiter">);</span>
   for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>new_recipe<span class="Delimiter">.</span>steps<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    const instruction&amp; inst = new_recipe<span class="Delimiter">.</span>steps<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
+    instruction&amp; inst = new_recipe<span class="Delimiter">.</span>steps<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
     for <span class="Delimiter">(</span>long long int j = <span class="Constant">0</span><span class="Delimiter">;</span> j &lt; SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">);</span> ++j<span class="Delimiter">)</span>
-      ensure_all_concrete_types<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">).</span>type<span class="Delimiter">);</span>
+      ensure_all_concrete_types<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">),</span> exemplar<span class="Delimiter">);</span>
     for <span class="Delimiter">(</span>long long int j = <span class="Constant">0</span><span class="Delimiter">;</span> j &lt; SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++j<span class="Delimiter">)</span>
-      ensure_all_concrete_types<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">).</span>type<span class="Delimiter">);</span>
+      ensure_all_concrete_types<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">),</span> exemplar<span class="Delimiter">);</span>
   <span class="Delimiter">}</span>
 <span class="Delimiter">}</span>
 
-void ensure_all_concrete_types<span class="Delimiter">(</span>const type_tree* x<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-  if <span class="Delimiter">(</span>!x<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    raise &lt;&lt; <span class="Constant">&quot;null type</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
+void ensure_all_concrete_types<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">const</span><span class="Comment">*/</span> reagent&amp; x<span class="Delimiter">,</span> const recipe&amp; exemplar<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  if <span class="Delimiter">(</span>!x<span class="Delimiter">.</span>type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+    raise_error &lt;&lt; maybe<span class="Delimiter">(</span>exemplar<span class="Delimiter">.</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;failed to map a type to &quot;</span> &lt;&lt; x<span class="Delimiter">.</span>original_string &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
+    x<span class="Delimiter">.</span>type = new type_tree<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span>  <span class="Comment">// just to prevent crashes later</span>
     <span class="Identifier">return</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
-  if <span class="Delimiter">(</span>x<span class="Delimiter">-&gt;</span>value == -<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    raise &lt;&lt; <span class="Constant">&quot;unknown type</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
+  if <span class="Delimiter">(</span>x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value == -<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
+    raise_error &lt;&lt; maybe<span class="Delimiter">(</span>exemplar<span class="Delimiter">.</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;failed to map a type to the unknown &quot;</span> &lt;&lt; x<span class="Delimiter">.</span>original_string &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">return</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
 <span class="Delimiter">}</span>
 
+long long int non_ghost_size<span class="Delimiter">(</span>vector&lt;recipe_ordinal&gt;&amp; variants<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  long long int result = <span class="Constant">0</span><span class="Delimiter">;</span>
+  for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>variants<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
+    if <span class="Delimiter">(</span>variants<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)</span> != -<span class="Constant">1</span><span class="Delimiter">)</span> ++result<span class="Delimiter">;</span>
+  <span class="Identifier">return</span> result<span class="Delimiter">;</span>
+<span class="Delimiter">}</span>
+
 <span class="Delimiter">:(scenario shape_shifting_recipe_2)</span>
 recipe main [
   <span class="Constant">10</span>:point<span class="Special"> &lt;- </span>merge <span class="Constant">14</span><span class="Delimiter">,</span> <span class="Constant">15</span>
@@ -476,6 +543,147 @@ recipe foo a:_t <span class="Delimiter">-&gt;</span> b:_t [
   b<span class="Special"> &lt;- </span>copy a
 ]
 <span class="traceContains">+error: main: no call found for 'b:address:number &lt;- foo a'</span>
+
+<span class="Delimiter">:(scenario specialize_inside_recipe_without_header)</span>
+recipe main [
+  foo <span class="Constant">3</span>
+]
+recipe foo [
+  local-scope
+  x:number<span class="Special"> &lt;- </span>next-ingredient  <span class="Comment"># ensure no header</span>
+  <span class="Constant">1</span>:number/<span class="Special">raw &lt;- </span>bar x  <span class="Comment"># call a shape-shifting recipe</span>
+]
+recipe bar x:_elem <span class="Delimiter">-&gt;</span> y:_elem [
+  local-scope
+  load-ingredients
+  y<span class="Special"> &lt;- </span>add x<span class="Delimiter">,</span> <span class="Constant">1</span>
+]
+<span class="traceContains">+mem: storing 4 in location 1</span>
+
+<span class="Delimiter">:(scenario specialize_with_literal)</span>
+recipe main [
+  local-scope
+  <span class="Comment"># permit literal to map to number</span>
+  <span class="Constant">1</span>:number/<span class="Special">raw &lt;- </span>foo <span class="Constant">3</span>
+]
+recipe foo x:_elem <span class="Delimiter">-&gt;</span> y:_elem [
+  local-scope
+  load-ingredients
+  y<span class="Special"> &lt;- </span>add x<span class="Delimiter">,</span> <span class="Constant">1</span>
+]
+<span class="traceContains">+mem: storing 4 in location 1</span>
+
+<span class="Delimiter">:(scenario specialize_with_literal_2)</span>
+recipe main [
+  local-scope
+  <span class="Comment"># permit literal to map to character</span>
+  <span class="Constant">1</span>:character/<span class="Special">raw &lt;- </span>foo <span class="Constant">3</span>
+]
+recipe foo x:_elem <span class="Delimiter">-&gt;</span> y:_elem [
+  local-scope
+  load-ingredients
+  y<span class="Special"> &lt;- </span>add x<span class="Delimiter">,</span> <span class="Constant">1</span>
+]
+<span class="traceContains">+mem: storing 4 in location 1</span>
+
+<span class="Delimiter">:(scenario specialize_with_literal_3)</span>
+<span class="Special">% Hide_errors = true;</span>
+recipe main [
+  local-scope
+  <span class="Comment"># permit '0' to map to address to shape-shifting type-ingredient</span>
+  <span class="Constant">1</span>:address:character/<span class="Special">raw &lt;- </span>foo <span class="Constant">0</span>
+]
+recipe foo x:address:_elem <span class="Delimiter">-&gt;</span> y:address:_elem [
+  local-scope
+  load-ingredients
+  y<span class="Special"> &lt;- </span>copy x
+]
+<span class="traceContains">+mem: storing 0 in location 1</span>
+$error: <span class="Constant">0</span>
+
+<span class="Delimiter">:(scenario specialize_with_literal_4)</span>
+<span class="Special">% Hide_errors = true;</span>
+recipe main [
+  local-scope
+  <span class="Comment"># ambiguous call: what's the type of its ingredient?!</span>
+  foo <span class="Constant">0</span>
+]
+recipe foo x:address:_elem <span class="Delimiter">-&gt;</span> y:address:_elem [
+  local-scope
+  load-ingredients
+  y<span class="Special"> &lt;- </span>copy x
+]
+<span class="traceContains">+error: foo: failed to map a type to x</span>
+<span class="traceContains">+error: foo: failed to map a type to y</span>
+
+<span class="Delimiter">:(scenario specialize_with_literal_5)</span>
+recipe main [
+  foo <span class="Constant">3</span><span class="Delimiter">,</span> <span class="Constant">4</span>  <span class="Comment"># recipe mapping two variables to literals</span>
+]
+recipe foo x:_elem<span class="Delimiter">,</span> y:_elem [
+  local-scope
+  load-ingredients
+  <span class="Constant">1</span>:number/<span class="Special">raw &lt;- </span>add x<span class="Delimiter">,</span> y
+]
+<span class="traceContains">+mem: storing 7 in location 1</span>
+
+<span class="Delimiter">:(scenario multiple_shape_shifting_variants)</span>
+<span class="Comment"># try to call two different shape-shifting recipes with the same name</span>
+recipe main [
+  e1:d1:number<span class="Special"> &lt;- </span>merge <span class="Constant">3</span>
+  e2:d2:number<span class="Special"> &lt;- </span>merge <span class="Constant">4</span><span class="Delimiter">,</span> <span class="Constant">5</span>
+  <span class="Constant">1</span>:number/<span class="Special">raw &lt;- </span>foo e1
+  <span class="Constant">2</span>:number/<span class="Special">raw &lt;- </span>foo e2
+]
+<span class="Comment"># the two shape-shifting definitions</span>
+recipe foo a:d1:_elem <span class="Delimiter">-&gt;</span> b:number [
+  local-scope
+  load-ingredients
+  reply <span class="Constant">34</span>
+]
+recipe foo a:d2:_elem <span class="Delimiter">-&gt;</span> b:number [
+  local-scope
+  load-ingredients
+  reply <span class="Constant">35</span>
+]
+<span class="Comment"># the shape-shifting containers they use</span>
+container d1:_elem [
+  x:_elem
+]
+container d2:_elem [
+  x:number
+  y:_elem
+]
+<span class="traceContains">+mem: storing 34 in location 1</span>
+<span class="traceContains">+mem: storing 35 in location 2</span>
+
+<span class="Delimiter">:(scenario multiple_shape_shifting_variants_2)</span>
+<span class="Comment"># static dispatch between shape-shifting variants, _including pointer lookups_</span>
+recipe main [
+  e1:d1:number<span class="Special"> &lt;- </span>merge <span class="Constant">3</span>
+  e2:address:d2:number<span class="Special"> &lt;- </span>new <span class="Delimiter">{(</span>d2 number<span class="Delimiter">)</span>: type<span class="Delimiter">}</span>
+  <span class="Constant">1</span>:number/<span class="Special">raw &lt;- </span>foo e1
+  <span class="Constant">2</span>:number/<span class="Special">raw &lt;- </span>foo *e2  <span class="Comment"># different from previous scenario</span>
+]
+recipe foo a:d1:_elem <span class="Delimiter">-&gt;</span> b:number [
+  local-scope
+  load-ingredients
+  reply <span class="Constant">34</span>
+]
+recipe foo a:d2:_elem <span class="Delimiter">-&gt;</span> b:number [
+  local-scope
+  load-ingredients
+  reply <span class="Constant">35</span>
+]
+container d1:_elem [
+  x:_elem
+]
+container d2:_elem [
+  x:number
+  y:_elem
+]
+<span class="traceContains">+mem: storing 34 in location 1</span>
+<span class="traceContains">+mem: storing 35 in location 2</span>
 </pre>
 </body>
 </html>