about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-11-10 19:56:41 -0800
committerKartik K. Agaram <vc@akkartik.com>2015-11-10 19:56:41 -0800
commit0c1791a950f6ba1cdfdab9b5104f80fad85cb8e8 (patch)
treea7f32fe967455af476ad13a492ac9e8567043d7e
parentc1585c88fa61918a9c464f7d6eb5b1b4b107048b (diff)
downloadmu-0c1791a950f6ba1cdfdab9b5104f80fad85cb8e8.tar.gz
2418 - start raising errors on generic calls
-rw-r--r--057static_dispatch.cc13
-rw-r--r--059generic_recipe.cc44
2 files changed, 38 insertions, 19 deletions
diff --git a/057static_dispatch.cc b/057static_dispatch.cc
index 2047db7a..27a9d32f 100644
--- a/057static_dispatch.cc
+++ b/057static_dispatch.cc
@@ -110,18 +110,19 @@ Transform.push_back(resolve_ambiguous_calls);  // idempotent
 
 :(code)
 void resolve_ambiguous_calls(recipe_ordinal r) {
-  if (!get(Recipe, r).has_header) return;
-  trace(9991, "transform") << "--- resolve ambiguous calls for recipe " << get(Recipe, r).name << end();
-  for (long long int index = 0; index < SIZE(get(Recipe, r).steps); ++index) {
-    instruction& inst = get(Recipe, r).steps.at(index);
+  recipe& caller_recipe = get(Recipe, r);
+  if (!caller_recipe.has_header) return;
+  trace(9991, "transform") << "--- resolve ambiguous calls for recipe " << caller_recipe.name << end();
+  for (long long int index = 0; index < SIZE(caller_recipe.steps); ++index) {
+    instruction& inst = caller_recipe.steps.at(index);
     if (inst.is_label) continue;
     if (!contains_key(Recipe_variants, inst.name)) continue;
     assert(!get(Recipe_variants, inst.name).empty());
-    replace_best_variant(inst);
+    replace_best_variant(inst, caller_recipe);
   }
 }
 
-void replace_best_variant(instruction& inst) {
+void replace_best_variant(instruction& inst, const recipe& caller_recipe) {
   trace(9992, "transform") << "instruction " << inst.name << end();
   vector<recipe_ordinal>& variants = get(Recipe_variants, inst.name);
   long long int best_score = variant_score(inst, get(Recipe_ordinal, inst.name));
diff --git a/059generic_recipe.cc b/059generic_recipe.cc
index add37757..87b1151c 100644
--- a/059generic_recipe.cc
+++ b/059generic_recipe.cc
@@ -38,7 +38,7 @@ if (best_score == -1) {
   recipe_ordinal exemplar = pick_matching_generic_variant(variants, inst, best_score);
   if (exemplar) {
     trace(9992, "transform") << "found variant to specialize: " << exemplar << ' ' << get(Recipe, exemplar).name << end();
-    variants.push_back(new_variant(exemplar, inst));
+    variants.push_back(new_variant(exemplar, inst, caller_recipe));
     inst.name = get(Recipe, variants.back()).name;
     trace(9992, "transform") << "new specialization: " << inst.name << end();
   }
@@ -124,7 +124,7 @@ bool is_type_ingredient_name(const string& type) {
   return !type.empty() && type.at(0) == '_';
 }
 
-recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst) {
+recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst, const recipe& caller_recipe) {
   string new_name = next_unused_recipe_name(inst.name);
   trace(9993, "transform") << "switching " << inst.name << " to " << new_name << end();
   assert(!contains_key(Recipe_ordinal, new_name));
@@ -142,10 +142,12 @@ recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst) {
   // that gives enough information to replace type-ingredients with concrete types
   {
     map<string, const string_tree*> mappings;
-    compute_type_ingredient_mappings(get(Recipe, exemplar), inst, mappings);
-    replace_type_ingredients(new_recipe, mappings);
+    bool error = false;
+    compute_type_ingredient_mappings(get(Recipe, exemplar), inst, mappings, caller_recipe, &error);
+    if (!error) replace_type_ingredients(new_recipe, mappings);
     for (map<string, const string_tree*>::iterator p = mappings.begin(); p != mappings.end(); ++p)
       delete p->second;
+    if (error) return exemplar;
   }
   ensure_all_concrete_types(new_recipe);
   // finally, perform all transforms on the new specialization
@@ -190,29 +192,29 @@ void save_or_deduce_type_name(reagent& x, map<string, string_tree*>& type_name)
   trace(9993, "transform") << "type of " << x.name << " is " << debug_string(x.properties.at(0).second) << end();
 }
 
-void compute_type_ingredient_mappings(const recipe& exemplar, const instruction& inst, map<string, const string_tree*>& mappings) {
+void compute_type_ingredient_mappings(const recipe& exemplar, const instruction& inst, map<string, const string_tree*>& mappings, const recipe& caller_recipe, bool* error) {
   for (long long int i = 0; i < SIZE(exemplar.ingredients); ++i) {
     const reagent& base = exemplar.ingredients.at(i);
     reagent ingredient = inst.ingredients.at(i);
     assert(ingredient.properties.at(0).second);
     canonize_type(ingredient);
-    accumulate_type_ingredients(base, ingredient, mappings, exemplar);
+    accumulate_type_ingredients(base, ingredient, mappings, exemplar, inst, caller_recipe, error);
   }
   for (long long int i = 0; i < SIZE(exemplar.products); ++i) {
     const reagent& base = exemplar.products.at(i);
     reagent product = inst.products.at(i);
     assert(product.properties.at(0).second);
     canonize_type(product);
-    accumulate_type_ingredients(base, product, mappings, exemplar);
+    accumulate_type_ingredients(base, product, mappings, exemplar, inst, caller_recipe, error);
   }
 }
 
-void accumulate_type_ingredients(const reagent& base, reagent& refinement, map<string, const string_tree*>& mappings, const recipe& exemplar) {
+void accumulate_type_ingredients(const reagent& base, reagent& refinement, map<string, const string_tree*>& mappings, const recipe& exemplar, const instruction& call_instruction, const recipe& caller_recipe, bool* error) {
   assert(refinement.properties.at(0).second);
-  accumulate_type_ingredients(base.properties.at(0).second, refinement.properties.at(0).second, mappings, exemplar, base);
+  accumulate_type_ingredients(base.properties.at(0).second, refinement.properties.at(0).second, mappings, exemplar, base, call_instruction, caller_recipe, error);
 }
 
-void accumulate_type_ingredients(const string_tree* base, const string_tree* refinement, map<string, const string_tree*>& mappings, const recipe& exemplar, const reagent& r) {
+void accumulate_type_ingredients(const string_tree* base, const string_tree* refinement, map<string, const string_tree*>& mappings, const recipe& exemplar, const reagent& r, const instruction& call_instruction, const recipe& caller_recipe, bool* error) {
   if (!base) return;
   if (!refinement) {
     raise_error << maybe(exemplar.name) << "missing type ingredient in " << r.original_string << '\n' << end();
@@ -229,13 +231,17 @@ void accumulate_type_ingredients(const string_tree* base, const string_tree* ref
       put(mappings, base->value, new string_tree(*refinement));
     }
     else {
-      assert(deeply_equal(get(mappings, base->value), refinement));
+      if (!deeply_equal(get(mappings, base->value), refinement)) {
+        raise_error << maybe(caller_recipe.name) << "no call found for '" << call_instruction.to_string() << "'\n" << end();
+        *error = true;
+        return;
+      }
     }
   }
   else {
-    accumulate_type_ingredients(base->left, refinement->left, mappings, exemplar, r);
+    accumulate_type_ingredients(base->left, refinement->left, mappings, exemplar, r, call_instruction, caller_recipe, error);
   }
-  accumulate_type_ingredients(base->right, refinement->right, mappings, exemplar, r);
+  accumulate_type_ingredients(base->right, refinement->right, mappings, exemplar, r, call_instruction, caller_recipe, error);
 }
 
 void replace_type_ingredients(recipe& new_recipe, const map<string, const string_tree*>& mappings) {
@@ -424,3 +430,15 @@ recipe bar a:_t -> result:_t [
   result <- copy a
 ]
 +mem: storing 34 in location 5
+
+:(scenario generic_recipe_error)
+% Hide_errors = true;
+recipe main [
+  a:number <- copy 3
+  b:address:number <- foo a
+]
+recipe foo a:_t -> b:_t [
+  load-ingredients
+  b <- copy a
+]
++error: main: no call found for 'b:address:number <- foo a'