From 850822ffbfd441d05161452be28b54f882b1b378 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 1 Nov 2017 03:41:16 -0700 Subject: 4102 --- html/054static_dispatch.cc.html | 948 ++++++++++++++++++++-------------------- 1 file changed, 477 insertions(+), 471 deletions(-) (limited to 'html/054static_dispatch.cc.html') diff --git a/html/054static_dispatch.cc.html b/html/054static_dispatch.cc.html index 15d4d181..12306ed6 100644 --- a/html/054static_dispatch.cc.html +++ b/html/054static_dispatch.cc.html @@ -15,6 +15,7 @@ body { font-size: 12pt; font-family: monospace; color: #aaaaaa; background-color a { color:#eeeeee; text-decoration: none; } a:hover { text-decoration: underline; } * { font-size: 12pt; font-size: 1em; } +.CommentedCode { color: #6c6c6c; } .muRecipe { color: #ff8700; } .muData { color: #ffff00; } .LineNr { color: #444444; } @@ -231,7 +232,7 @@ if ('onhashchange' in window) { 166 for (int index = 0; index < SIZE(caller_recipe.steps); ++index) { 167 ¦ instruction& inst = caller_recipe.steps.at(index); 168 ¦ if (inst.is_label) continue; -169 ¦ if (non_ghost_size(get_or_insert(Recipe_variants, inst.name)) == 0) continue; +169 ¦ if (non_ghost_size(get_or_insert(Recipe_variants, inst.name)) == 0) continue; 170 ¦ trace(9992, "transform") << "instruction " << to_original_string(inst) << end(); 171 ¦ Resolve_stack.push_front(call(r)); 172 ¦ Resolve_stack.front().running_step_index = index; @@ -245,511 +246,516 @@ if ('onhashchange' in window) { 180 } 181 182 string best_variant(instruction& inst, const recipe& caller_recipe) { -183 vector<recipe_ordinal>& variants = get(Recipe_variants, inst.name); +183 const vector<recipe_ordinal>& variants = get(Recipe_variants, inst.name); 184 vector<recipe_ordinal> candidates; 185 186 // Static Dispatch Phase 1 -187 candidates = strictly_matching_variants(inst, variants); -188 if (!candidates.empty()) return best_variant(inst, candidates).name; -189 -190 // Static Dispatch Phase 2 -191 candidates = strictly_matching_variants_except_literal_against_address_or_boolean(inst, variants); -192 if (!candidates.empty()) return best_variant(inst, candidates).name; -193 -194 // Static Dispatch Phase 3 -195 //: (shape-shifting recipes in a later layer) -196 // End Static Dispatch Phase 3 -197 -198 // Static Dispatch Phase 4 -199 candidates = matching_variants(inst, variants); -200 if (!candidates.empty()) return best_variant(inst, candidates).name; -201 -202 // error messages -203 if (get(Recipe_ordinal, inst.name) >= MAX_PRIMITIVE_RECIPES) { // we currently don't check types for primitive variants -204 ¦ if (SIZE(variants) == 1) { -205 ¦ ¦ raise << maybe(caller_recipe.name) << "types don't match in call for '" << to_original_string(inst) << "'\n" << end(); -206 ¦ ¦ raise << " which tries to call '" << original_header_label(get(Recipe, variants.at(0))) << "'\n" << end(); -207 ¦ } -208 ¦ else { -209 ¦ ¦ raise << maybe(caller_recipe.name) << "failed to find a matching call for '" << to_original_string(inst) << "'\n" << end(); -210 ¦ ¦ raise << " available variants are:\n" << end(); -211 ¦ ¦ for (int i = 0; i < SIZE(variants); ++i) -212 ¦ ¦ ¦ raise << " " << original_header_label(get(Recipe, variants.at(i))) << '\n' << end(); -213 ¦ } -214 ¦ for (list<call>::iterator p = /*skip*/++Resolve_stack.begin(); p != Resolve_stack.end(); ++p) { -215 ¦ ¦ const recipe& specializer_recipe = get(Recipe, p->running_recipe); -216 ¦ ¦ const instruction& specializer_inst = specializer_recipe.steps.at(p->running_step_index); -217 ¦ ¦ if (specializer_recipe.name != "interactive") -218 ¦ ¦ ¦ raise << " (from '" << to_original_string(specializer_inst) << "' in " << specializer_recipe.name << ")\n" << end(); -219 ¦ ¦ else -220 ¦ ¦ ¦ raise << " (from '" << to_original_string(specializer_inst) << "')\n" << end(); -221 ¦ ¦ // One special-case to help with the rewrite_stash transform. (cross-layer) -222 ¦ ¦ if (specializer_inst.products.at(0).name.find("stash_") == 0) { -223 ¦ ¦ ¦ instruction stash_inst; -224 ¦ ¦ ¦ if (next_stash(*p, &stash_inst)) { -225 ¦ ¦ ¦ ¦ if (specializer_recipe.name != "interactive") -226 ¦ ¦ ¦ ¦ ¦ raise << " (part of '" << to_original_string(stash_inst) << "' in " << specializer_recipe.name << ")\n" << end(); -227 ¦ ¦ ¦ ¦ else -228 ¦ ¦ ¦ ¦ ¦ raise << " (part of '" << to_original_string(stash_inst) << "')\n" << end(); -229 ¦ ¦ ¦ } -230 ¦ ¦ } -231 ¦ } -232 } -233 return ""; -234 } -235 -236 // phase 1 -237 vector<recipe_ordinal> strictly_matching_variants(const instruction& inst, vector<recipe_ordinal>& variants) { -238 vector<recipe_ordinal> result; -239 for (int i = 0; i < SIZE(variants); ++i) { -240 ¦ if (variants.at(i) == -1) continue; -241 ¦ trace(9992, "transform") << "checking variant (strict) " << i << ": " << header_label(variants.at(i)) << end(); -242 ¦ if (all_header_reagents_strictly_match(inst, get(Recipe, variants.at(i)))) -243 ¦ ¦ result.push_back(variants.at(i)); -244 } -245 return result; -246 } -247 -248 bool all_header_reagents_strictly_match(const instruction& inst, const recipe& variant) { -249 for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { -250 ¦ if (!types_strictly_match(variant.ingredients.at(i), inst.ingredients.at(i))) { -251 ¦ ¦ trace(9993, "transform") << "strict match failed: ingredient " << i << end(); -252 ¦ ¦ return false; -253 ¦ } -254 } -255 for (int i = 0; i < min(SIZE(inst.products), SIZE(variant.products)); ++i) { -256 ¦ if (is_dummy(inst.products.at(i))) continue; -257 ¦ if (!types_strictly_match(variant.products.at(i), inst.products.at(i))) { -258 ¦ ¦ trace(9993, "transform") << "strict match failed: product " << i << end(); -259 ¦ ¦ return false; -260 ¦ } -261 } -262 return true; -263 } -264 -265 // phase 2 -266 vector<recipe_ordinal> strictly_matching_variants_except_literal_against_address_or_boolean(const instruction& inst, vector<recipe_ordinal>& variants) { -267 vector<recipe_ordinal> result; -268 for (int i = 0; i < SIZE(variants); ++i) { -269 ¦ if (variants.at(i) == -1) continue; -270 ¦ trace(9992, "transform") << "checking variant (strict except literal-against-boolean) " << i << ": " << header_label(variants.at(i)) << end(); -271 ¦ if (all_header_reagents_strictly_match_except_literal_against_address_or_boolean(inst, get(Recipe, variants.at(i)))) -272 ¦ ¦ result.push_back(variants.at(i)); -273 } -274 return result; -275 } -276 -277 bool all_header_reagents_strictly_match_except_literal_against_address_or_boolean(const instruction& inst, const recipe& variant) { -278 for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { -279 ¦ if (!types_strictly_match_except_literal_against_address_or_boolean(variant.ingredients.at(i), inst.ingredients.at(i))) { -280 ¦ ¦ trace(9993, "transform") << "match failed: ingredient " << i << end(); -281 ¦ ¦ return false; -282 ¦ } -283 } -284 for (int i = 0; i < min(SIZE(variant.products), SIZE(inst.products)); ++i) { -285 ¦ if (is_dummy(inst.products.at(i))) continue; -286 ¦ if (!types_strictly_match_except_literal_against_address_or_boolean(variant.products.at(i), inst.products.at(i))) { -287 ¦ ¦ trace(9993, "transform") << "match failed: product " << i << end(); -288 ¦ ¦ return false; -289 ¦ } -290 } -291 return true; -292 } -293 -294 bool types_strictly_match_except_literal_against_address_or_boolean(const reagent& to, const reagent& from) { -295 if (is_literal(from) && is_mu_boolean(to)) -296 ¦ return from.name == "0" || from.name == "1"; -297 // Match Literal Zero Against Address { -298 if (is_literal(from) && is_mu_address(to)) -299 ¦ return from.name == "0"; -300 // } -301 return types_strictly_match(to, from); -302 } -303 -304 // phase 4 -305 vector<recipe_ordinal> matching_variants(const instruction& inst, vector<recipe_ordinal>& variants) { -306 vector<recipe_ordinal> result; -307 for (int i = 0; i < SIZE(variants); ++i) { -308 ¦ if (variants.at(i) == -1) continue; -309 ¦ trace(9992, "transform") << "checking variant " << i << ": " << header_label(variants.at(i)) << end(); -310 ¦ if (all_header_reagents_match(inst, get(Recipe, variants.at(i)))) -311 ¦ ¦ result.push_back(variants.at(i)); -312 } -313 return result; -314 } -315 -316 bool all_header_reagents_match(const instruction& inst, const recipe& variant) { -317 for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { -318 ¦ if (!types_match(variant.ingredients.at(i), inst.ingredients.at(i))) { -319 ¦ ¦ trace(9993, "transform") << "match failed: ingredient " << i << end(); -320 ¦ ¦ return false; -321 ¦ } -322 } -323 for (int i = 0; i < min(SIZE(variant.products), SIZE(inst.products)); ++i) { -324 ¦ if (is_dummy(inst.products.at(i))) continue; -325 ¦ if (!types_match(variant.products.at(i), inst.products.at(i))) { -326 ¦ ¦ trace(9993, "transform") << "match failed: product " << i << end(); -327 ¦ ¦ return false; -328 ¦ } -329 } -330 return true; -331 } -332 -333 // tie-breaker for each phase -334 const recipe& best_variant(const instruction& inst, vector<recipe_ordinal>& candidates) { -335 assert(!candidates.empty()); -336 int min_score = 999; -337 int min_index = 0; -338 for (int i = 0; i < SIZE(candidates); ++i) { -339 ¦ const recipe& candidate = get(Recipe, candidates.at(i)); -340 ¦ // prefer functions without extra or missing ingredients or products -341 ¦ int score = abs(SIZE(candidate.products)-SIZE(inst.products)) -342 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ + abs(SIZE(candidate.ingredients)-SIZE(inst.ingredients)); -343 ¦ // prefer functions with non-address ingredients or products -344 ¦ for (int j = 0; j < SIZE(candidate.ingredients); ++j) { -345 ¦ ¦ if (is_mu_address(candidate.ingredients.at(j))) -346 ¦ ¦ ¦ ++score; -347 ¦ } -348 ¦ for (int j = 0; j < SIZE(candidate.products); ++j) { -349 ¦ ¦ if (is_mu_address(candidate.products.at(j))) -350 ¦ ¦ ¦ ++score; -351 ¦ } -352 ¦ assert(score < 999); -353 ¦ if (score < min_score) { -354 ¦ ¦ min_score = score; -355 ¦ ¦ min_index = i; +187 //? cerr << inst.name << " phase 1\n"; +188 candidates = strictly_matching_variants(inst, variants); +189 if (!candidates.empty()) return best_variant(inst, candidates).name; +190 +191 // Static Dispatch Phase 2 +192 //? cerr << inst.name << " phase 2\n"; +193 candidates = strictly_matching_variants_except_literal_against_address_or_boolean(inst, variants); +194 if (!candidates.empty()) return best_variant(inst, candidates).name; +195 +196 //? cerr << inst.name << " phase 3\n"; +197 // Static Dispatch Phase 3 +198 //: (shape-shifting recipes in a later layer) +199 // End Static Dispatch Phase 3 +200 +201 // Static Dispatch Phase 4 +202 //? cerr << inst.name << " phase 4\n"; +203 candidates = matching_variants(inst, variants); +204 if (!candidates.empty()) return best_variant(inst, candidates).name; +205 +206 // error messages +207 if (!is_primitive(get(Recipe_ordinal, inst.name))) { // we currently don't check types for primitive variants +208 ¦ if (SIZE(variants) == 1) { +209 ¦ ¦ raise << maybe(caller_recipe.name) << "types don't match in call for '" << to_original_string(inst) << "'\n" << end(); +210 ¦ ¦ raise << " which tries to call '" << original_header_label(get(Recipe, variants.at(0))) << "'\n" << end(); +211 ¦ } +212 ¦ else { +213 ¦ ¦ raise << maybe(caller_recipe.name) << "failed to find a matching call for '" << to_original_string(inst) << "'\n" << end(); +214 ¦ ¦ raise << " available variants are:\n" << end(); +215 ¦ ¦ for (int i = 0; i < SIZE(variants); ++i) +216 ¦ ¦ ¦ raise << " " << original_header_label(get(Recipe, variants.at(i))) << '\n' << end(); +217 ¦ } +218 ¦ for (list<call>::iterator p = /*skip*/++Resolve_stack.begin(); p != Resolve_stack.end(); ++p) { +219 ¦ ¦ const recipe& specializer_recipe = get(Recipe, p->running_recipe); +220 ¦ ¦ const instruction& specializer_inst = specializer_recipe.steps.at(p->running_step_index); +221 ¦ ¦ if (specializer_recipe.name != "interactive") +222 ¦ ¦ ¦ raise << " (from '" << to_original_string(specializer_inst) << "' in " << specializer_recipe.name << ")\n" << end(); +223 ¦ ¦ else +224 ¦ ¦ ¦ raise << " (from '" << to_original_string(specializer_inst) << "')\n" << end(); +225 ¦ ¦ // One special-case to help with the rewrite_stash transform. (cross-layer) +226 ¦ ¦ if (specializer_inst.products.at(0).name.find("stash_") == 0) { +227 ¦ ¦ ¦ instruction stash_inst; +228 ¦ ¦ ¦ if (next_stash(*p, &stash_inst)) { +229 ¦ ¦ ¦ ¦ if (specializer_recipe.name != "interactive") +230 ¦ ¦ ¦ ¦ ¦ raise << " (part of '" << to_original_string(stash_inst) << "' in " << specializer_recipe.name << ")\n" << end(); +231 ¦ ¦ ¦ ¦ else +232 ¦ ¦ ¦ ¦ ¦ raise << " (part of '" << to_original_string(stash_inst) << "')\n" << end(); +233 ¦ ¦ ¦ } +234 ¦ ¦ } +235 ¦ } +236 } +237 return ""; +238 } +239 +240 // phase 1 +241 vector<recipe_ordinal> strictly_matching_variants(const instruction& inst, const vector<recipe_ordinal>& variants) { +242 vector<recipe_ordinal> result; +243 for (int i = 0; i < SIZE(variants); ++i) { +244 ¦ if (variants.at(i) == -1) continue; +245 ¦ trace(9992, "transform") << "checking variant (strict) " << i << ": " << header_label(variants.at(i)) << end(); +246 ¦ if (all_header_reagents_strictly_match(inst, get(Recipe, variants.at(i)))) +247 ¦ ¦ result.push_back(variants.at(i)); +248 } +249 return result; +250 } +251 +252 bool all_header_reagents_strictly_match(const instruction& inst, const recipe& variant) { +253 for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { +254 ¦ if (!types_strictly_match(variant.ingredients.at(i), inst.ingredients.at(i))) { +255 ¦ ¦ trace(9993, "transform") << "strict match failed: ingredient " << i << end(); +256 ¦ ¦ return false; +257 ¦ } +258 } +259 for (int i = 0; i < min(SIZE(inst.products), SIZE(variant.products)); ++i) { +260 ¦ if (is_dummy(inst.products.at(i))) continue; +261 ¦ if (!types_strictly_match(variant.products.at(i), inst.products.at(i))) { +262 ¦ ¦ trace(9993, "transform") << "strict match failed: product " << i << end(); +263 ¦ ¦ return false; +264 ¦ } +265 } +266 return true; +267 } +268 +269 // phase 2 +270 vector<recipe_ordinal> strictly_matching_variants_except_literal_against_address_or_boolean(const instruction& inst, const vector<recipe_ordinal>& variants) { +271 vector<recipe_ordinal> result; +272 for (int i = 0; i < SIZE(variants); ++i) { +273 ¦ if (variants.at(i) == -1) continue; +274 ¦ trace(9992, "transform") << "checking variant (strict except literal-against-boolean) " << i << ": " << header_label(variants.at(i)) << end(); +275 ¦ if (all_header_reagents_strictly_match_except_literal_against_address_or_boolean(inst, get(Recipe, variants.at(i)))) +276 ¦ ¦ result.push_back(variants.at(i)); +277 } +278 return result; +279 } +280 +281 bool all_header_reagents_strictly_match_except_literal_against_address_or_boolean(const instruction& inst, const recipe& variant) { +282 for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { +283 ¦ if (!types_strictly_match_except_literal_against_address_or_boolean(variant.ingredients.at(i), inst.ingredients.at(i))) { +284 ¦ ¦ trace(9993, "transform") << "match failed: ingredient " << i << end(); +285 ¦ ¦ return false; +286 ¦ } +287 } +288 for (int i = 0; i < min(SIZE(variant.products), SIZE(inst.products)); ++i) { +289 ¦ if (is_dummy(inst.products.at(i))) continue; +290 ¦ if (!types_strictly_match_except_literal_against_address_or_boolean(variant.products.at(i), inst.products.at(i))) { +291 ¦ ¦ trace(9993, "transform") << "match failed: product " << i << end(); +292 ¦ ¦ return false; +293 ¦ } +294 } +295 return true; +296 } +297 +298 bool types_strictly_match_except_literal_against_address_or_boolean(const reagent& to, const reagent& from) { +299 if (is_literal(from) && is_mu_boolean(to)) +300 ¦ return from.name == "0" || from.name == "1"; +301 // Match Literal Zero Against Address { +302 if (is_literal(from) && is_mu_address(to)) +303 ¦ return from.name == "0"; +304 // } +305 return types_strictly_match(to, from); +306 } +307 +308 // phase 4 +309 vector<recipe_ordinal> matching_variants(const instruction& inst, const vector<recipe_ordinal>& variants) { +310 vector<recipe_ordinal> result; +311 for (int i = 0; i < SIZE(variants); ++i) { +312 ¦ if (variants.at(i) == -1) continue; +313 ¦ trace(9992, "transform") << "checking variant " << i << ": " << header_label(variants.at(i)) << end(); +314 ¦ if (all_header_reagents_match(inst, get(Recipe, variants.at(i)))) +315 ¦ ¦ result.push_back(variants.at(i)); +316 } +317 return result; +318 } +319 +320 bool all_header_reagents_match(const instruction& inst, const recipe& variant) { +321 for (int i = 0; i < min(SIZE(inst.ingredients), SIZE(variant.ingredients)); ++i) { +322 ¦ if (!types_match(variant.ingredients.at(i), inst.ingredients.at(i))) { +323 ¦ ¦ trace(9993, "transform") << "match failed: ingredient " << i << end(); +324 ¦ ¦ return false; +325 ¦ } +326 } +327 for (int i = 0; i < min(SIZE(variant.products), SIZE(inst.products)); ++i) { +328 ¦ if (is_dummy(inst.products.at(i))) continue; +329 ¦ if (!types_match(variant.products.at(i), inst.products.at(i))) { +330 ¦ ¦ trace(9993, "transform") << "match failed: product " << i << end(); +331 ¦ ¦ return false; +332 ¦ } +333 } +334 return true; +335 } +336 +337 // tie-breaker for each phase +338 const recipe& best_variant(const instruction& inst, vector<recipe_ordinal>& candidates) { +339 assert(!candidates.empty()); +340 if (SIZE(candidates) == 1) return get(Recipe, candidates.at(0)); +341 int min_score = 999; +342 int min_index = 0; +343 for (int i = 0; i < SIZE(candidates); ++i) { +344 ¦ const recipe& candidate = get(Recipe, candidates.at(i)); +345 ¦ // prefer functions without extra or missing ingredients or products +346 ¦ int score = abs(SIZE(candidate.products)-SIZE(inst.products)) +347 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ + abs(SIZE(candidate.ingredients)-SIZE(inst.ingredients)); +348 ¦ // prefer functions with non-address ingredients or products +349 ¦ for (int j = 0; j < SIZE(candidate.ingredients); ++j) { +350 ¦ ¦ if (is_mu_address(candidate.ingredients.at(j))) +351 ¦ ¦ ¦ ++score; +352 ¦ } +353 ¦ for (int j = 0; j < SIZE(candidate.products); ++j) { +354 ¦ ¦ if (is_mu_address(candidate.products.at(j))) +355 ¦ ¦ ¦ ++score; 356 ¦ } -357 } -358 return get(Recipe, candidates.at(min_index)); -359 } -360 -361 int non_ghost_size(vector<recipe_ordinal>& variants) { -362 int result = 0; -363 for (int i = 0; i < SIZE(variants); ++i) -364 ¦ if (variants.at(i) != -1) ++result; -365 return result; -366 } -367 -368 bool next_stash(const call& c, instruction* stash_inst) { -369 const recipe& specializer_recipe = get(Recipe, c.running_recipe); -370 int index = c.running_step_index; -371 for (++index; index < SIZE(specializer_recipe.steps); ++index) { -372 ¦ const instruction& inst = specializer_recipe.steps.at(index); -373 ¦ if (inst.name == "stash") { -374 ¦ ¦ *stash_inst = inst; -375 ¦ ¦ return true; -376 ¦ } -377 } -378 return false; -379 } -380 -381 :(scenario static_dispatch_disabled_in_recipe_without_variants) -382 def main [ -383 1:num <- test 3 -384 ] -385 def test [ -386 2:num <- next-ingredient # ensure no header -387 return 34 -388 ] -389 +mem: storing 34 in location 1 -390 -391 :(scenario static_dispatch_disabled_on_headerless_definition) -392 % Hide_errors = true; -393 def test a:num -> z:num [ -394 z <- copy 1 -395 ] -396 def test [ -397 return 34 -398 ] -399 +error: redefining recipe test -400 -401 :(scenario static_dispatch_disabled_on_headerless_definition_2) -402 % Hide_errors = true; -403 def test [ -404 return 34 -405 ] -406 def test a:num -> z:num [ -407 z <- copy 1 -408 ] -409 +error: redefining recipe test -410 -411 :(scenario static_dispatch_on_primitive_names) -412 def main [ -413 1:num <- copy 34 -414 2:num <- copy 34 -415 3:bool <- equal 1:num, 2:num -416 4:bool <- copy 0/false -417 5:bool <- copy 0/false -418 6:bool <- equal 4:bool, 5:bool -419 ] -420 # temporarily hardcode number equality to always fail -421 def equal x:num, y:num -> z:bool [ -422 local-scope -423 load-ingredients -424 z <- copy 0/false -425 ] -426 # comparing numbers used overload -427 +mem: storing 0 in location 3 -428 # comparing booleans continues to use primitive -429 +mem: storing 1 in location 6 -430 -431 :(scenario static_dispatch_works_with_dummy_results_for_containers) -432 def main [ -433 _ <- test 3, 4 -434 ] -435 def test a:num -> z:point [ -436 local-scope -437 load-ingredients -438 z <- merge a, 0 +357 ¦ assert(score < 999); +358 ¦ if (score < min_score) { +359 ¦ ¦ min_score = score; +360 ¦ ¦ min_index = i; +361 ¦ } +362 } +363 return get(Recipe, candidates.at(min_index)); +364 } +365 +366 int non_ghost_size(vector<recipe_ordinal>& variants) { +367 int result = 0; +368 for (int i = 0; i < SIZE(variants); ++i) +369 ¦ if (variants.at(i) != -1) ++result; +370 return result; +371 } +372 +373 bool next_stash(const call& c, instruction* stash_inst) { +374 const recipe& specializer_recipe = get(Recipe, c.running_recipe); +375 int index = c.running_step_index; +376 for (++index; index < SIZE(specializer_recipe.steps); ++index) { +377 ¦ const instruction& inst = specializer_recipe.steps.at(index); +378 ¦ if (inst.name == "stash") { +379 ¦ ¦ *stash_inst = inst; +380 ¦ ¦ return true; +381 ¦ } +382 } +383 return false; +384 } +385 +386 :(scenario static_dispatch_disabled_in_recipe_without_variants) +387 def main [ +388 1:num <- test 3 +389 ] +390 def test [ +391 2:num <- next-ingredient # ensure no header +392 return 34 +393 ] +394 +mem: storing 34 in location 1 +395 +396 :(scenario static_dispatch_disabled_on_headerless_definition) +397 % Hide_errors = true; +398 def test a:num -> z:num [ +399 z <- copy 1 +400 ] +401 def test [ +402 return 34 +403 ] +404 +error: redefining recipe test +405 +406 :(scenario static_dispatch_disabled_on_headerless_definition_2) +407 % Hide_errors = true; +408 def test [ +409 return 34 +410 ] +411 def test a:num -> z:num [ +412 z <- copy 1 +413 ] +414 +error: redefining recipe test +415 +416 :(scenario static_dispatch_on_primitive_names) +417 def main [ +418 1:num <- copy 34 +419 2:num <- copy 34 +420 3:bool <- equal 1:num, 2:num +421 4:bool <- copy 0/false +422 5:bool <- copy 0/false +423 6:bool <- equal 4:bool, 5:bool +424 ] +425 # temporarily hardcode number equality to always fail +426 def equal x:num, y:num -> z:bool [ +427 local-scope +428 load-ingredients +429 z <- copy 0/false +430 ] +431 # comparing numbers used overload +432 +mem: storing 0 in location 3 +433 # comparing booleans continues to use primitive +434 +mem: storing 1 in location 6 +435 +436 :(scenario static_dispatch_works_with_dummy_results_for_containers) +437 def main [ +438 _ <- test 3, 4 439 ] -440 def test a:num, b:num -> z:point [ +440 def test a:num -> z:point [ 441 local-scope 442 load-ingredients -443 z <- merge a, b +443 z <- merge a, 0 444 ] -445 $error: 0 -446 -447 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_first_use) -448 def main [ -449 x:&:foo <- new foo:type -450 test x -451 ] -452 container foo [ -453 x:num -454 ] -455 def test a:&:foo -> z:num [ -456 local-scope -457 load-ingredients -458 z:num <- get *a, x:offset +445 def test a:num, b:num -> z:point [ +446 local-scope +447 load-ingredients +448 z <- merge a, b +449 ] +450 $error: 0 +451 +452 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_first_use) +453 def main [ +454 x:&:foo <- new foo:type +455 test x +456 ] +457 container foo [ +458 x:num 459 ] -460 $error: 0 -461 -462 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_second_use) -463 def main [ -464 x:&:foo <- new foo:type -465 test x -466 ] -467 def test a:&:foo -> z:num [ -468 local-scope -469 load-ingredients -470 z:num <- get *a, x:offset +460 def test a:&:foo -> z:num [ +461 local-scope +462 load-ingredients +463 z:num <- get *a, x:offset +464 ] +465 $error: 0 +466 +467 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_second_use) +468 def main [ +469 x:&:foo <- new foo:type +470 test x 471 ] -472 container foo [ -473 x:num -474 ] -475 $error: 0 -476 -477 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses) -478 def main [ -479 1:num <- foo 0 -480 ] -481 def foo x:&:num -> y:num [ -482 return 34 -483 ] -484 def foo x:num -> y:num [ -485 return 35 -486 ] -487 +mem: storing 35 in location 1 -488 -489 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses_2) -490 def main [ -491 1:num <- foo 0 0 -492 ] -493 # Both variants need to bind 0 to address in first ingredient. -494 # We still want to prefer the variant with a number rather than address for -495 # _subsequent_ ingredients. -496 def foo x:&:num y:&:num -> z:num [ # put the bad match before the good one -497 return 34 -498 ] -499 def foo x:&:num y:num -> z:num [ -500 return 35 -501 ] -502 +mem: storing 35 in location 1 -503 -504 :(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers) -505 % Hide_errors = true; -506 def main [ -507 local-scope -508 x:char <- copy 10/newline -509 1:num/raw <- foo x -510 ] -511 def foo x:num -> y:num [ -512 load-ingredients -513 return 34 -514 ] -515 +error: main: ingredient 0 has the wrong type at '1:num/raw <- foo x' -516 -mem: storing 34 in location 1 -517 -518 :(scenario static_dispatch_dispatches_literal_to_boolean_before_character) -519 def main [ -520 1:num/raw <- foo 0 # valid literal for boolean -521 ] -522 def foo x:char -> y:num [ -523 local-scope -524 load-ingredients -525 return 34 +472 def test a:&:foo -> z:num [ +473 local-scope +474 load-ingredients +475 z:num <- get *a, x:offset +476 ] +477 container foo [ +478 x:num +479 ] +480 $error: 0 +481 +482 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses) +483 def main [ +484 1:num <- foo 0 +485 ] +486 def foo x:&:num -> y:num [ +487 return 34 +488 ] +489 def foo x:num -> y:num [ +490 return 35 +491 ] +492 +mem: storing 35 in location 1 +493 +494 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses_2) +495 def main [ +496 1:num <- foo 0 0 +497 ] +498 # Both variants need to bind 0 to address in first ingredient. +499 # We still want to prefer the variant with a number rather than address for +500 # _subsequent_ ingredients. +501 def foo x:&:num y:&:num -> z:num [ # put the bad match before the good one +502 return 34 +503 ] +504 def foo x:&:num y:num -> z:num [ +505 return 35 +506 ] +507 +mem: storing 35 in location 1 +508 +509 :(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers) +510 % Hide_errors = true; +511 def main [ +512 local-scope +513 x:char <- copy 10/newline +514 1:num/raw <- foo x +515 ] +516 def foo x:num -> y:num [ +517 load-ingredients +518 return 34 +519 ] +520 +error: main: ingredient 0 has the wrong type at '1:num/raw <- foo x' +521 -mem: storing 34 in location 1 +522 +523 :(scenario static_dispatch_dispatches_literal_to_boolean_before_character) +524 def main [ +525 1:num/raw <- foo 0 # valid literal for boolean 526 ] -527 def foo x:bool -> y:num [ +527 def foo x:char -> y:num [ 528 local-scope 529 load-ingredients -530 return 35 +530 return 34 531 ] -532 # boolean variant is preferred -533 +mem: storing 35 in location 1 -534 -535 :(scenario static_dispatch_dispatches_literal_to_character_when_out_of_boolean_range) -536 def main [ -537 1:num/raw <- foo 97 # not a valid literal for boolean -538 ] -539 def foo x:char -> y:num [ -540 local-scope -541 load-ingredients -542 return 34 +532 def foo x:bool -> y:num [ +533 local-scope +534 load-ingredients +535 return 35 +536 ] +537 # boolean variant is preferred +538 +mem: storing 35 in location 1 +539 +540 :(scenario static_dispatch_dispatches_literal_to_character_when_out_of_boolean_range) +541 def main [ +542 1:num/raw <- foo 97 # not a valid literal for boolean 543 ] -544 def foo x:bool -> y:num [ +544 def foo x:char -> y:num [ 545 local-scope 546 load-ingredients -547 return 35 +547 return 34 548 ] -549 # character variant is preferred -550 +mem: storing 34 in location 1 -551 -552 :(scenario static_dispatch_dispatches_literal_to_number_if_at_all_possible) -553 def main [ -554 1:num/raw <- foo 97 -555 ] -556 def foo x:char -> y:num [ -557 local-scope -558 load-ingredients -559 return 34 +549 def foo x:bool -> y:num [ +550 local-scope +551 load-ingredients +552 return 35 +553 ] +554 # character variant is preferred +555 +mem: storing 34 in location 1 +556 +557 :(scenario static_dispatch_dispatches_literal_to_number_if_at_all_possible) +558 def main [ +559 1:num/raw <- foo 97 560 ] -561 def foo x:num -> y:num [ +561 def foo x:char -> y:num [ 562 local-scope 563 load-ingredients -564 return 35 +564 return 34 565 ] -566 # number variant is preferred -567 +mem: storing 35 in location 1 -568 -569 :(replace{} "string header_label(const recipe_ordinal r)") -570 string header_label(const recipe_ordinal r) { -571 return header_label(get(Recipe, r)); -572 } -573 :(code) -574 string header_label(const recipe& caller) { -575 ostringstream out; -576 out << "recipe " << caller.name; -577 for (int i = 0; i < SIZE(caller.ingredients); ++i) -578 ¦ out << ' ' << to_string(caller.ingredients.at(i)); -579 if (!caller.products.empty()) out << " ->"; -580 for (int i = 0; i < SIZE(caller.products); ++i) -581 ¦ out << ' ' << to_string(caller.products.at(i)); -582 return out.str(); -583 } -584 -585 string original_header_label(const recipe& caller) { -586 ostringstream out; -587 out << "recipe " << caller.original_name; -588 for (int i = 0; i < SIZE(caller.ingredients); ++i) -589 ¦ out << ' ' << caller.ingredients.at(i).original_string; -590 if (!caller.products.empty()) out << " ->"; -591 for (int i = 0; i < SIZE(caller.products); ++i) -592 ¦ out << ' ' << caller.products.at(i).original_string; -593 return out.str(); -594 } -595 -596 :(scenario reload_variant_retains_other_variants) -597 def main [ -598 1:num <- copy 34 -599 2:num <- foo 1:num -600 ] -601 def foo x:num -> y:num [ -602 local-scope -603 load-ingredients -604 return 34 +566 def foo x:num -> y:num [ +567 local-scope +568 load-ingredients +569 return 35 +570 ] +571 # number variant is preferred +572 +mem: storing 35 in location 1 +573 +574 :(replace{} "string header_label(const recipe_ordinal r)") +575 string header_label(const recipe_ordinal r) { +576 return header_label(get(Recipe, r)); +577 } +578 :(code) +579 string header_label(const recipe& caller) { +580 ostringstream out; +581 out << "recipe " << caller.name; +582 for (int i = 0; i < SIZE(caller.ingredients); ++i) +583 ¦ out << ' ' << to_string(caller.ingredients.at(i)); +584 if (!caller.products.empty()) out << " ->"; +585 for (int i = 0; i < SIZE(caller.products); ++i) +586 ¦ out << ' ' << to_string(caller.products.at(i)); +587 return out.str(); +588 } +589 +590 string original_header_label(const recipe& caller) { +591 ostringstream out; +592 out << "recipe " << caller.original_name; +593 for (int i = 0; i < SIZE(caller.ingredients); ++i) +594 ¦ out << ' ' << caller.ingredients.at(i).original_string; +595 if (!caller.products.empty()) out << " ->"; +596 for (int i = 0; i < SIZE(caller.products); ++i) +597 ¦ out << ' ' << caller.products.at(i).original_string; +598 return out.str(); +599 } +600 +601 :(scenario reload_variant_retains_other_variants) +602 def main [ +603 1:num <- copy 34 +604 2:num <- foo 1:num 605 ] -606 def foo x:&:num -> y:num [ +606 def foo x:num -> y:num [ 607 local-scope 608 load-ingredients -609 return 35 +609 return 34 610 ] -611 def! foo x:&:num -> y:num [ +611 def foo x:&:num -> y:num [ 612 local-scope 613 load-ingredients -614 return 36 +614 return 35 615 ] -616 +mem: storing 34 in location 2 -617 $error: 0 -618 -619 :(scenario dispatch_errors_come_after_unknown_name_errors) -620 % Hide_errors = true; -621 def main [ -622 y:num <- foo x -623 ] -624 def foo a:num -> b:num [ -625 local-scope -626 load-ingredients -627 return 34 +616 def! foo x:&:num -> y:num [ +617 local-scope +618 load-ingredients +619 return 36 +620 ] +621 +mem: storing 34 in location 2 +622 $error: 0 +623 +624 :(scenario dispatch_errors_come_after_unknown_name_errors) +625 % Hide_errors = true; +626 def main [ +627 y:num <- foo x 628 ] -629 def foo a:bool -> b:num [ +629 def foo a:num -> b:num [ 630 local-scope 631 load-ingredients -632 return 35 +632 return 34 633 ] -634 +error: main: missing type for 'x' in 'y:num <- foo x' -635 +error: main: failed to find a matching call for 'y:num <- foo x' -636 -637 :(scenario override_methods_with_type_abbreviations) -638 def main [ -639 local-scope -640 s:text <- new [abc] -641 1:num/raw <- foo s -642 ] -643 def foo a:address:array:character -> result:number [ -644 return 34 -645 ] -646 # identical to previous variant once you take type abbreviations into account -647 def! foo a:text -> result:num [ -648 return 35 -649 ] -650 +mem: storing 35 in location 1 -651 -652 :(scenario ignore_static_dispatch_in_type_errors_without_overloading) -653 % Hide_errors = true; -654 def main [ -655 local-scope -656 x:&:num <- copy 0 -657 foo x -658 ] -659 def foo x:&:char [ +634 def foo a:bool -> b:num [ +635 local-scope +636 load-ingredients +637 return 35 +638 ] +639 +error: main: missing type for 'x' in 'y:num <- foo x' +640 +error: main: failed to find a matching call for 'y:num <- foo x' +641 +642 :(scenario override_methods_with_type_abbreviations) +643 def main [ +644 local-scope +645 s:text <- new [abc] +646 1:num/raw <- foo s +647 ] +648 def foo a:address:array:character -> result:number [ +649 return 34 +650 ] +651 # identical to previous variant once you take type abbreviations into account +652 def! foo a:text -> result:num [ +653 return 35 +654 ] +655 +mem: storing 35 in location 1 +656 +657 :(scenario ignore_static_dispatch_in_type_errors_without_overloading) +658 % Hide_errors = true; +659 def main [ 660 local-scope -661 load-ingredients -662 ] -663 +error: main: types don't match in call for 'foo x' -664 +error: which tries to call 'recipe foo x:&:char' -665 -666 :(scenario show_available_variants_in_dispatch_errors) -667 % Hide_errors = true; -668 def main [ -669 local-scope -670 x:&:num <- copy 0 -671 foo x -672 ] -673 def foo x:&:char [ +661 x:&:num <- copy 0 +662 foo x +663 ] +664 def foo x:&:char [ +665 local-scope +666 load-ingredients +667 ] +668 +error: main: types don't match in call for 'foo x' +669 +error: which tries to call 'recipe foo x:&:char' +670 +671 :(scenario show_available_variants_in_dispatch_errors) +672 % Hide_errors = true; +673 def main [ 674 local-scope -675 load-ingredients -676 ] -677 def foo x:&:bool [ -678 local-scope -679 load-ingredients -680 ] -681 +error: main: failed to find a matching call for 'foo x' -682 +error: available variants are: -683 +error: recipe foo x:&:char -684 +error: recipe foo x:&:bool -685 -686 :(before "End Includes") -687 using std::abs; +675 x:&:num <- copy 0 +676 foo x +677 ] +678 def foo x:&:char [ +679 local-scope +680 load-ingredients +681 ] +682 def foo x:&:bool [ +683 local-scope +684 load-ingredients +685 ] +686 +error: main: failed to find a matching call for 'foo x' +687 +error: available variants are: +688 +error: recipe foo x:&:char +689 +error: recipe foo x:&:bool +690 +691 :(before "End Includes") +692 using std::abs; -- cgit 1.4.1-2-gfad0