diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-05-05 21:47:59 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-05-05 21:59:50 -0700 |
commit | e76a27f3edfa0703a204f3ab30ce01b58877f6af (patch) | |
tree | b9ff84216ac81d78b6d14dbbf7211981cb30e153 | |
parent | 5d5116e3343b5f6efa289e35e1c29b761db12068 (diff) | |
download | mu-e76a27f3edfa0703a204f3ab30ce01b58877f6af.tar.gz |
2929 - fix a bug in static dispatch
Thanks Caleb for finding this. We'd been using sandboxes for so long, I hadn't tried a null/0 screen/console in a while and somewhere down the road Mu stopped matching 0 against concrete addresses.
-rw-r--r-- | 021check_instruction.cc | 9 | ||||
-rw-r--r-- | 056static_dispatch.cc | 74 | ||||
-rw-r--r-- | 058shape_shifting_recipe.cc | 24 |
3 files changed, 84 insertions, 23 deletions
diff --git a/021check_instruction.cc b/021check_instruction.cc index 138aa733..599fa6c9 100644 --- a/021check_instruction.cc +++ b/021check_instruction.cc @@ -123,15 +123,6 @@ bool types_match(const reagent& to, const reagent& from) { return types_strictly_match(to, from); } -bool types_strictly_match_except_literal_against_boolean(const reagent& to, const reagent& from) { - // 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) - && to.type && to.type->value == get(Type_ordinal, "boolean")) - return boolean_matches_literal(to, from); - return types_strictly_match(to, from); -} - bool boolean_matches_literal(const reagent& to, const reagent& from) { if (!is_literal(from)) return false; if (!to.type) return false; diff --git a/056static_dispatch.cc b/056static_dispatch.cc index 353b4b50..5271fe13 100644 --- a/056static_dispatch.cc +++ b/056static_dispatch.cc @@ -175,14 +175,18 @@ string best_variant(instruction& inst, const recipe& caller_recipe) { if (!candidates.empty()) return best_variant(inst, candidates).name; // Static Dispatch Phase 2 - //: (shape-shifting recipes in a later layer) - // End Static Dispatch Phase 2 + candidates = strictly_matching_variants_except_literal_zero_against_address(inst, variants); + if (!candidates.empty()) return best_variant(inst, candidates).name; // Static Dispatch Phase 3 - candidates = strictly_matching_variants_except_literal_against_boolean(inst, variants); - if (!candidates.empty()) return best_variant(inst, candidates).name; + //: (shape-shifting recipes in a later layer) + // End Static Dispatch Phase 3 // Static Dispatch Phase 4 + candidates = strictly_matching_variants_except_literal_against_address_or_boolean(inst, variants); + if (!candidates.empty()) return best_variant(inst, candidates).name; + + // Static Dispatch Phase 5 candidates = matching_variants(inst, variants); if (!candidates.empty()) return best_variant(inst, candidates).name; @@ -240,28 +244,65 @@ bool all_header_reagents_strictly_match(const instruction& inst, const recipe& v return true; } -// phase 3 -vector<recipe_ordinal> strictly_matching_variants_except_literal_against_boolean(const instruction& inst, vector<recipe_ordinal>& variants) { +// phase 2 +vector<recipe_ordinal> strictly_matching_variants_except_literal_zero_against_address(const instruction& inst, vector<recipe_ordinal>& variants) { + vector<recipe_ordinal> result; + for (int i = 0; i < SIZE(variants); ++i) { + if (variants.at(i) == -1) continue; + trace(9992, "transform") << "checking variant (strict) " << i << ": " << header_label(variants.at(i)) << end(); + if (all_header_reagents_strictly_match_except_literal_zero_against_address(inst, get(Recipe, variants.at(i)))) + result.push_back(variants.at(i)); + } + return result; +} + +bool all_header_reagents_strictly_match_except_literal_zero_against_address(const instruction& inst, const recipe& variant) { + for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { + if (!types_strictly_match_except_literal_zero_against_address(variant.ingredients.at(i), inst.ingredients.at(i))) { + trace(9993, "transform") << "strict match failed: ingredient " << i << end(); + return false; + } + } + for (int i = 0; i < min(SIZE(inst.products), SIZE(variant.products)); ++i) { + if (is_dummy(inst.products.at(i))) continue; + if (!types_strictly_match(variant.products.at(i), inst.products.at(i))) { + trace(9993, "transform") << "strict match failed: product " << i << end(); + return false; + } + } + return true; +} + +bool types_strictly_match_except_literal_zero_against_address(const reagent& to, const reagent& from) { + // 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 types_strictly_match(to, from); +} + +// phase 4 +vector<recipe_ordinal> strictly_matching_variants_except_literal_against_address_or_boolean(const instruction& inst, vector<recipe_ordinal>& variants) { vector<recipe_ordinal> result; for (int i = 0; i < SIZE(variants); ++i) { if (variants.at(i) == -1) continue; trace(9992, "transform") << "checking variant (strict except literals-against-booleans) " << i << ": " << header_label(variants.at(i)) << end(); - if (all_header_reagents_strictly_match_except_literal_against_boolean(inst, get(Recipe, variants.at(i)))) + if (all_header_reagents_strictly_match_except_literal_against_address_or_boolean(inst, get(Recipe, variants.at(i)))) result.push_back(variants.at(i)); } return result; } -bool all_header_reagents_strictly_match_except_literal_against_boolean(const instruction& inst, const recipe& variant) { +bool all_header_reagents_strictly_match_except_literal_against_address_or_boolean(const instruction& inst, const recipe& variant) { for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { - if (!types_strictly_match_except_literal_against_boolean(variant.ingredients.at(i), inst.ingredients.at(i))) { + if (!types_strictly_match_except_literal_against_address_or_boolean(variant.ingredients.at(i), inst.ingredients.at(i))) { trace(9993, "transform") << "strict match failed: ingredient " << i << end(); return false; } } for (int i = 0; i < min(SIZE(variant.products), SIZE(inst.products)); ++i) { if (is_dummy(inst.products.at(i))) continue; - if (!types_strictly_match_except_literal_against_boolean(variant.products.at(i), inst.products.at(i))) { + if (!types_strictly_match_except_literal_against_address_or_boolean(variant.products.at(i), inst.products.at(i))) { trace(9993, "transform") << "strict match failed: product " << i << end(); return false; } @@ -269,7 +310,18 @@ bool all_header_reagents_strictly_match_except_literal_against_boolean(const ins return true; } -// phase 4 +bool types_strictly_match_except_literal_against_address_or_boolean(const reagent& to, const reagent& from) { + // 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) + && 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 types_strictly_match(to, from); +} + +// phase 5 vector<recipe_ordinal> matching_variants(const instruction& inst, vector<recipe_ordinal>& variants) { vector<recipe_ordinal> result; for (int i = 0; i < SIZE(variants); ++i) { diff --git a/058shape_shifting_recipe.cc b/058shape_shifting_recipe.cc index 433147cd..5f87e6da 100644 --- a/058shape_shifting_recipe.cc +++ b/058shape_shifting_recipe.cc @@ -48,7 +48,7 @@ string original_name; :(before "End Load Recipe Name") result.original_name = result.name; -:(after "Static Dispatch Phase 2") +:(after "Static Dispatch Phase 3") candidates = strictly_matching_shape_shifting_variants(inst, variants); if (!candidates.empty()) { recipe_ordinal exemplar = best_shape_shifting_variant(inst, candidates); @@ -778,8 +778,7 @@ def foo x:address:_elem -> y:address:_elem [ load-ingredients y <- copy x ] -+error: foo: failed to map a type to x -+error: foo: failed to map a type to y ++error: main: instruction foo has no valid specialization :(scenario specialize_with_literal_5) def main [ @@ -996,6 +995,25 @@ def foo x:address:_elem -> y:number [ # prefer the concrete variant, ignore concrete types in scoring the shape-shifting variant +mem: storing 34 in location 1 +:(scenario specialize_literal_as_address) +def main [ + 1:number <- foo 0 +] +# variant with concrete address type +def foo x:address:number -> y:number [ + local-scope + load-ingredients + return 34 +] +# shape-shifting variant +def foo x:address:_elem -> y:number [ + local-scope + load-ingredients + return 35 +] +# prefer the concrete variant, ignore concrete types in scoring the shape-shifting variant ++mem: storing 34 in location 1 + :(scenario missing_type_during_specialization) % Hide_errors = true; # define a shape-shifting recipe |