diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-05-24 19:14:01 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-05-24 19:14:01 -0700 |
commit | e38b7a998955dac52d53ac20eead3854974efdf2 (patch) | |
tree | af72b95cf86a56a46ab8bc31788663612a92d70d | |
parent | c43b455d24c9a9418b05245b4917b608793701a9 (diff) | |
download | mu-e38b7a998955dac52d53ac20eead3854974efdf2.tar.gz |
3003
Bugfix: overriding a primitive recipe with a generic variant that takes an address of something shouldn't mask the primitive when you call it with literal 0.
-rw-r--r-- | 054static_dispatch.cc | 4 | ||||
-rw-r--r-- | 056shape_shifting_recipe.cc | 30 |
2 files changed, 32 insertions, 2 deletions
diff --git a/054static_dispatch.cc b/054static_dispatch.cc index fa0c6c74..106c757a 100644 --- a/054static_dispatch.cc +++ b/054static_dispatch.cc @@ -277,7 +277,7 @@ bool types_strictly_match_except_literal_zero_against_address(const reagent& to, // to sidestep type-checking, use /unsafe in the source. // this will be highlighted in red inside vim. just for setting up some tests. if (is_literal(from) && is_mu_address(to)) - return from.name == "0"; + return from.name == "0" && !contains_type_ingredient_name(to); return types_strictly_match(to, from); } @@ -317,7 +317,7 @@ bool types_strictly_match_except_literal_against_address_or_boolean(const reagen && to.type && to.type->value == get(Type_ordinal, "boolean")) return boolean_matches_literal(to, from); if (is_literal(from) && is_mu_address(to)) - return from.name == "0"; + return from.name == "0" && !contains_type_ingredient_name(to); return types_strictly_match(to, from); } diff --git a/056shape_shifting_recipe.cc b/056shape_shifting_recipe.cc index bd804c6f..70a464e0 100644 --- a/056shape_shifting_recipe.cc +++ b/056shape_shifting_recipe.cc @@ -246,6 +246,7 @@ recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst, con map<string, const type_tree*> mappings; bool error = false; compute_type_ingredient_mappings(get(Recipe, exemplar), inst, mappings, caller_recipe, &error); + if (!error) error = (SIZE(mappings) != type_ingredient_count_in_header(exemplar)); if (!error) replace_type_ingredients(new_recipe, mappings); for (map<string, const type_tree*>::iterator p = mappings.begin(); p != mappings.end(); ++p) delete p->second; @@ -446,6 +447,23 @@ void replace_type_ingredients(type_tree* type, const map<string, const type_tree } } +int type_ingredient_count_in_header(recipe_ordinal variant) { + const recipe& caller = get(Recipe, variant); + set<string> type_ingredients; + for (int i = 0; i < SIZE(caller.ingredients); ++i) + accumulate_type_ingredients(caller.ingredients.at(i).type, type_ingredients); + for (int i = 0; i < SIZE(caller.products); ++i) + accumulate_type_ingredients(caller.products.at(i).type, type_ingredients); + return SIZE(type_ingredients); +} + +void accumulate_type_ingredients(const type_tree* type, set<string>& out) { + if (!type) return; + if (is_type_ingredient_name(type->name)) out.insert(type->name); + accumulate_type_ingredients(type->left, out); + accumulate_type_ingredients(type->right, out); +} + type_tree* parse_type_tree(const string& s) { istringstream in(s); in >> std::noskipws; @@ -1072,3 +1090,15 @@ def main [ foo 34 ] $error: 0 + +:(scenario shape_shifting_recipe_coexists_with_primitive) +# recipe overloading a primitive with a generic type +def add a:address:foo:_elem [ + assert 0, [should not get here] +] + +def main [ + # call primitive add with literal 0 + add 0, 0 +] +$error: 0 |