From 3b82206fd6143da6be50ff5f3c7e4c050039548a Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sun, 12 Mar 2017 13:02:12 -0700 Subject: 3792 Bugfix: make sure 'print 0, 0' always does the right thing, no matter how it's overloaded. Thanks Ella Couch for reporting this. --- 054static_dispatch.cc | 25 ++ html/054static_dispatch.cc.html | 559 +++++++++++++++++++++------------------- 2 files changed, 317 insertions(+), 267 deletions(-) diff --git a/054static_dispatch.cc b/054static_dispatch.cc index 0eb66443..7fdfa391 100644 --- a/054static_dispatch.cc +++ b/054static_dispatch.cc @@ -321,8 +321,18 @@ const recipe& best_variant(const instruction& inst, vector& cand int min_index = 0; for (int i = 0; i < SIZE(candidates); ++i) { const recipe& candidate = get(Recipe, candidates.at(i)); + // prefer functions without extra or missing ingredients or products int score = abs(SIZE(candidate.products)-SIZE(inst.products)) + abs(SIZE(candidate.ingredients)-SIZE(inst.ingredients)); + // prefer functions with non-address ingredients or products + for (int i = 0; i < SIZE(candidate.ingredients); ++i) { + if (is_mu_address(candidate.ingredients.at(i))) + ++score; + } + for (int i = 0; i < SIZE(candidate.products); ++i) { + if (is_mu_address(candidate.products.at(i))) + ++score; + } assert(score < 999); if (score < min_score) { min_score = score; @@ -460,6 +470,21 @@ def foo x:num -> y:num [ ] +mem: storing 35 in location 1 +:(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses_2) +def main [ + 1:num <- foo 0 0 +] +# Both variants need to bind 0 to address in first ingredient. +# We still want to prefer the variant with a number rather than address for +# _subsequent_ ingredients. +def foo x:&:num y:&:num -> z:num [ # put the bad match before the good one + return 34 +] +def foo x:&:num y:num -> z:num [ + return 35 +] ++mem: storing 35 in location 1 + :(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers) % Hide_errors = true; def main [ diff --git a/html/054static_dispatch.cc.html b/html/054static_dispatch.cc.html index 63e81390..f3723be9 100644 --- a/html/054static_dispatch.cc.html +++ b/html/054static_dispatch.cc.html @@ -224,7 +224,7 @@ if ('onhashchange' in window) { 159 for (int index = 0; index < SIZE(caller_recipe.steps); ++index) { 160 ¦ instruction& inst = caller_recipe.steps.at(index); 161 ¦ if (inst.is_label) continue; -162 ¦ if (non_ghost_size(get_or_insert(Recipe_variants, inst.name)) == 0) continue; +162 ¦ if (non_ghost_size(get_or_insert(Recipe_variants, inst.name)) == 0) continue; 163 ¦ trace(9992, "transform") << "instruction " << inst.original_string << end(); 164 ¦ Resolve_stack.push_front(call(r)); 165 ¦ Resolve_stack.front().running_step_index = index; @@ -270,7 +270,7 @@ if ('onhashchange' in window) { 205 ¦ ¦ // One special-case to help with the rewrite_stash transform. (cross-layer) 206 ¦ ¦ if (specializer_inst.products.at(0).name.find("stash_") == 0) { 207 ¦ ¦ ¦ instruction stash_inst; -208 ¦ ¦ ¦ if (next_stash(*p, &stash_inst)) { +208 ¦ ¦ ¦ if (next_stash(*p, &stash_inst)) { 209 ¦ ¦ ¦ ¦ if (specializer_recipe.name != "interactive") 210 ¦ ¦ ¦ ¦ ¦ raise << " (part of '" << stash_inst.original_string << "' in " << specializer_recipe.name << ")\n" << end(); 211 ¦ ¦ ¦ ¦ else @@ -386,283 +386,308 @@ if ('onhashchange' in window) { 321 int min_index = 0; 322 for (int i = 0; i < SIZE(candidates); ++i) { 323 ¦ const recipe& candidate = get(Recipe, candidates.at(i)); -324 ¦ int score = abs(SIZE(candidate.products)-SIZE(inst.products)) -325 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ + abs(SIZE(candidate.ingredients)-SIZE(inst.ingredients)); -326 ¦ assert(score < 999); -327 ¦ if (score < min_score) { -328 ¦ ¦ min_score = score; -329 ¦ ¦ min_index = i; -330 ¦ } -331 } -332 return get(Recipe, candidates.at(min_index)); -333 } -334 -335 int non_ghost_size(vector<recipe_ordinal>& variants) { -336 int result = 0; -337 for (int i = 0; i < SIZE(variants); ++i) -338 ¦ if (variants.at(i) != -1) ++result; -339 return result; -340 } -341 -342 bool next_stash(const call& c, instruction* stash_inst) { -343 const recipe& specializer_recipe = get(Recipe, c.running_recipe); -344 int index = c.running_step_index; -345 for (++index; index < SIZE(specializer_recipe.steps); ++index) { -346 ¦ const instruction& inst = specializer_recipe.steps.at(index); -347 ¦ if (inst.name == "stash") { -348 ¦ ¦ *stash_inst = inst; -349 ¦ ¦ return true; -350 ¦ } -351 } -352 return false; -353 } -354 -355 :(scenario static_dispatch_disabled_in_recipe_without_variants) -356 def main [ -357 1:num <- test 3 -358 ] -359 def test [ -360 2:num <- next-ingredient # ensure no header -361 return 34 -362 ] -363 +mem: storing 34 in location 1 +324 ¦ // prefer functions without extra or missing ingredients or products +325 ¦ int score = abs(SIZE(candidate.products)-SIZE(inst.products)) +326 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ + abs(SIZE(candidate.ingredients)-SIZE(inst.ingredients)); +327 ¦ // prefer functions with non-address ingredients or products +328 ¦ for (int i = 0; i < SIZE(candidate.ingredients); ++i) { +329 ¦ ¦ if (is_mu_address(candidate.ingredients.at(i))) +330 ¦ ¦ ¦ ++score; +331 ¦ } +332 ¦ for (int i = 0; i < SIZE(candidate.products); ++i) { +333 ¦ ¦ if (is_mu_address(candidate.products.at(i))) +334 ¦ ¦ ¦ ++score; +335 ¦ } +336 ¦ assert(score < 999); +337 ¦ if (score < min_score) { +338 ¦ ¦ min_score = score; +339 ¦ ¦ min_index = i; +340 ¦ } +341 } +342 return get(Recipe, candidates.at(min_index)); +343 } +344 +345 int non_ghost_size(vector<recipe_ordinal>& variants) { +346 int result = 0; +347 for (int i = 0; i < SIZE(variants); ++i) +348 ¦ if (variants.at(i) != -1) ++result; +349 return result; +350 } +351 +352 bool next_stash(const call& c, instruction* stash_inst) { +353 const recipe& specializer_recipe = get(Recipe, c.running_recipe); +354 int index = c.running_step_index; +355 for (++index; index < SIZE(specializer_recipe.steps); ++index) { +356 ¦ const instruction& inst = specializer_recipe.steps.at(index); +357 ¦ if (inst.name == "stash") { +358 ¦ ¦ *stash_inst = inst; +359 ¦ ¦ return true; +360 ¦ } +361 } +362 return false; +363 } 364 -365 :(scenario static_dispatch_disabled_on_headerless_definition) -366 % Hide_errors = true; -367 def test a:num -> z:num [ -368 z <- copy 1 -369 ] -370 def test [ +365 :(scenario static_dispatch_disabled_in_recipe_without_variants) +366 def main [ +367 1:num <- test 3 +368 ] +369 def test [ +370 2:num <- next-ingredient # ensure no header 371 return 34 372 ] -373 +error: redefining recipe test +373 +mem: storing 34 in location 1 374 -375 :(scenario static_dispatch_disabled_on_headerless_definition_2) +375 :(scenario static_dispatch_disabled_on_headerless_definition) 376 % Hide_errors = true; -377 def test [ -378 return 34 +377 def test a:num -> z:num [ +378 z <- copy 1 379 ] -380 def test a:num -> z:num [ -381 z <- copy 1 +380 def test [ +381 return 34 382 ] 383 +error: redefining recipe test 384 -385 :(scenario static_dispatch_on_primitive_names) -386 def main [ -387 1:num <- copy 34 -388 2:num <- copy 34 -389 3:bool <- equal 1:num, 2:num -390 4:bool <- copy 0/false -391 5:bool <- copy 0/false -392 6:bool <- equal 4:bool, 5:bool -393 ] -394 # temporarily hardcode number equality to always fail -395 def equal x:num, y:num -> z:bool [ -396 local-scope -397 load-ingredients -398 z <- copy 0/false -399 ] -400 # comparing numbers used overload -401 +mem: storing 0 in location 3 -402 # comparing booleans continues to use primitive -403 +mem: storing 1 in location 6 -404 -405 :(scenario static_dispatch_works_with_dummy_results_for_containers) -406 def main [ -407 _ <- test 3, 4 -408 ] -409 def test a:num -> z:point [ -410 local-scope -411 load-ingredients -412 z <- merge a, 0 -413 ] -414 def test a:num, b:num -> z:point [ -415 local-scope -416 load-ingredients -417 z <- merge a, b +385 :(scenario static_dispatch_disabled_on_headerless_definition_2) +386 % Hide_errors = true; +387 def test [ +388 return 34 +389 ] +390 def test a:num -> z:num [ +391 z <- copy 1 +392 ] +393 +error: redefining recipe test +394 +395 :(scenario static_dispatch_on_primitive_names) +396 def main [ +397 1:num <- copy 34 +398 2:num <- copy 34 +399 3:bool <- equal 1:num, 2:num +400 4:bool <- copy 0/false +401 5:bool <- copy 0/false +402 6:bool <- equal 4:bool, 5:bool +403 ] +404 # temporarily hardcode number equality to always fail +405 def equal x:num, y:num -> z:bool [ +406 local-scope +407 load-ingredients +408 z <- copy 0/false +409 ] +410 # comparing numbers used overload +411 +mem: storing 0 in location 3 +412 # comparing booleans continues to use primitive +413 +mem: storing 1 in location 6 +414 +415 :(scenario static_dispatch_works_with_dummy_results_for_containers) +416 def main [ +417 _ <- test 3, 4 418 ] -419 $error: 0 -420 -421 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_first_use) -422 def main [ -423 x:&:foo <- new foo:type -424 test x -425 ] -426 container foo [ -427 x:num +419 def test a:num -> z:point [ +420 local-scope +421 load-ingredients +422 z <- merge a, 0 +423 ] +424 def test a:num, b:num -> z:point [ +425 local-scope +426 load-ingredients +427 z <- merge a, b 428 ] -429 def test a:&:foo -> z:num [ -430 local-scope -431 load-ingredients -432 z:num <- get *a, x:offset -433 ] -434 $error: 0 -435 -436 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_second_use) -437 def main [ -438 x:&:foo <- new foo:type -439 test x -440 ] -441 def test a:&:foo -> z:num [ -442 local-scope -443 load-ingredients -444 z:num <- get *a, x:offset -445 ] -446 container foo [ -447 x:num -448 ] -449 $error: 0 -450 -451 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses) -452 def main [ -453 1:num <- foo 0 -454 ] -455 def foo x:&:num -> y:num [ -456 return 34 -457 ] -458 def foo x:num -> y:num [ -459 return 35 -460 ] -461 +mem: storing 35 in location 1 -462 -463 :(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers) -464 % Hide_errors = true; -465 def main [ -466 local-scope -467 x:char <- copy 10/newline -468 1:num/raw <- foo x -469 ] -470 def foo x:num -> y:num [ -471 load-ingredients -472 return 34 -473 ] -474 +error: main: ingredient 0 has the wrong type at '1:num/raw <- foo x' -475 -mem: storing 34 in location 1 -476 -477 :(scenario static_dispatch_dispatches_literal_to_boolean_before_character) -478 def main [ -479 1:num/raw <- foo 0 # valid literal for boolean -480 ] -481 def foo x:char -> y:num [ -482 local-scope -483 load-ingredients -484 return 34 +429 $error: 0 +430 +431 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_first_use) +432 def main [ +433 x:&:foo <- new foo:type +434 test x +435 ] +436 container foo [ +437 x:num +438 ] +439 def test a:&:foo -> z:num [ +440 local-scope +441 load-ingredients +442 z:num <- get *a, x:offset +443 ] +444 $error: 0 +445 +446 :(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_second_use) +447 def main [ +448 x:&:foo <- new foo:type +449 test x +450 ] +451 def test a:&:foo -> z:num [ +452 local-scope +453 load-ingredients +454 z:num <- get *a, x:offset +455 ] +456 container foo [ +457 x:num +458 ] +459 $error: 0 +460 +461 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses) +462 def main [ +463 1:num <- foo 0 +464 ] +465 def foo x:&:num -> y:num [ +466 return 34 +467 ] +468 def foo x:num -> y:num [ +469 return 35 +470 ] +471 +mem: storing 35 in location 1 +472 +473 :(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses_2) +474 def main [ +475 1:num <- foo 0 0 +476 ] +477 # Both variants need to bind 0 to address in first ingredient. +478 # We still want to prefer the variant with a number rather than address for +479 # _subsequent_ ingredients. +480 def foo x:&:num y:&:num -> z:num [ # put the bad match before the good one +481 return 34 +482 ] +483 def foo x:&:num y:num -> z:num [ +484 return 35 485 ] -486 def foo x:bool -> y:num [ -487 local-scope -488 load-ingredients -489 return 35 -490 ] -491 # boolean variant is preferred -492 +mem: storing 35 in location 1 -493 -494 :(scenario static_dispatch_dispatches_literal_to_character_when_out_of_boolean_range) -495 def main [ -496 1:num/raw <- foo 97 # not a valid literal for boolean -497 ] -498 def foo x:char -> y:num [ -499 local-scope -500 load-ingredients -501 return 34 -502 ] -503 def foo x:bool -> y:num [ -504 local-scope -505 load-ingredients -506 return 35 -507 ] -508 # character variant is preferred -509 +mem: storing 34 in location 1 -510 -511 :(scenario static_dispatch_dispatches_literal_to_number_if_at_all_possible) -512 def main [ -513 1:num/raw <- foo 97 -514 ] -515 def foo x:char -> y:num [ -516 local-scope -517 load-ingredients -518 return 34 -519 ] -520 def foo x:num -> y:num [ -521 local-scope -522 load-ingredients -523 return 35 -524 ] -525 # number variant is preferred -526 +mem: storing 35 in location 1 -527 -528 :(code) -529 string header_label(const recipe_ordinal r) { -530 return header_label(get(Recipe, r)); -531 } -532 string header_label(const recipe& caller) { -533 ostringstream out; -534 out << "recipe " << caller.name; -535 for (int i = 0; i < SIZE(caller.ingredients); ++i) -536 ¦ out << ' ' << to_string(caller.ingredients.at(i)); -537 if (!caller.products.empty()) out << " ->"; -538 for (int i = 0; i < SIZE(caller.products); ++i) -539 ¦ out << ' ' << to_string(caller.products.at(i)); -540 return out.str(); -541 } -542 -543 :(scenario reload_variant_retains_other_variants) -544 def main [ -545 1:num <- copy 34 -546 2:num <- foo 1:num -547 ] -548 def foo x:num -> y:num [ -549 local-scope -550 load-ingredients -551 return 34 -552 ] -553 def foo x:&:num -> y:num [ -554 local-scope -555 load-ingredients -556 return 35 -557 ] -558 def! foo x:&:num -> y:num [ -559 local-scope -560 load-ingredients -561 return 36 -562 ] -563 +mem: storing 34 in location 2 -564 $error: 0 -565 -566 :(scenario dispatch_errors_come_after_unknown_name_errors) -567 % Hide_errors = true; -568 def main [ -569 y:num <- foo x -570 ] -571 def foo a:num -> b:num [ -572 local-scope -573 load-ingredients -574 return 34 -575 ] -576 def foo a:bool -> b:num [ -577 local-scope -578 load-ingredients -579 return 35 -580 ] -581 +error: main: missing type for 'x' in 'y:num <- foo x' -582 +error: main: failed to find a matching call for 'y:num <- foo x' -583 -584 :(scenario override_methods_with_type_abbreviations) -585 def main [ -586 local-scope -587 s:text <- new [abc] -588 1:num/raw <- foo s -589 ] -590 def foo a:address:array:character -> result:number [ -591 return 34 -592 ] -593 # identical to previous variant once you take type abbreviations into account -594 def! foo a:text -> result:num [ -595 return 35 -596 ] -597 +mem: storing 35 in location 1 -598 -599 :(before "End Includes") -600 using std::abs; +486 +mem: storing 35 in location 1 +487 +488 :(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers) +489 % Hide_errors = true; +490 def main [ +491 local-scope +492 x:char <- copy 10/newline +493 1:num/raw <- foo x +494 ] +495 def foo x:num -> y:num [ +496 load-ingredients +497 return 34 +498 ] +499 +error: main: ingredient 0 has the wrong type at '1:num/raw <- foo x' +500 -mem: storing 34 in location 1 +501 +502 :(scenario static_dispatch_dispatches_literal_to_boolean_before_character) +503 def main [ +504 1:num/raw <- foo 0 # valid literal for boolean +505 ] +506 def foo x:char -> y:num [ +507 local-scope +508 load-ingredients +509 return 34 +510 ] +511 def foo x:bool -> y:num [ +512 local-scope +513 load-ingredients +514 return 35 +515 ] +516 # boolean variant is preferred +517 +mem: storing 35 in location 1 +518 +519 :(scenario static_dispatch_dispatches_literal_to_character_when_out_of_boolean_range) +520 def main [ +521 1:num/raw <- foo 97 # not a valid literal for boolean +522 ] +523 def foo x:char -> y:num [ +524 local-scope +525 load-ingredients +526 return 34 +527 ] +528 def foo x:bool -> y:num [ +529 local-scope +530 load-ingredients +531 return 35 +532 ] +533 # character variant is preferred +534 +mem: storing 34 in location 1 +535 +536 :(scenario static_dispatch_dispatches_literal_to_number_if_at_all_possible) +537 def main [ +538 1:num/raw <- foo 97 +539 ] +540 def foo x:char -> y:num [ +541 local-scope +542 load-ingredients +543 return 34 +544 ] +545 def foo x:num -> y:num [ +546 local-scope +547 load-ingredients +548 return 35 +549 ] +550 # number variant is preferred +551 +mem: storing 35 in location 1 +552 +553 :(code) +554 string header_label(const recipe_ordinal r) { +555 return header_label(get(Recipe, r)); +556 } +557 string header_label(const recipe& caller) { +558 ostringstream out; +559 out << "recipe " << caller.name; +560 for (int i = 0; i < SIZE(caller.ingredients); ++i) +561 ¦ out << ' ' << to_string(caller.ingredients.at(i)); +562 if (!caller.products.empty()) out << " ->"; +563 for (int i = 0; i < SIZE(caller.products); ++i) +564 ¦ out << ' ' << to_string(caller.products.at(i)); +565 return out.str(); +566 } +567 +568 :(scenario reload_variant_retains_other_variants) +569 def main [ +570 1:num <- copy 34 +571 2:num <- foo 1:num +572 ] +573 def foo x:num -> y:num [ +574 local-scope +575 load-ingredients +576 return 34 +577 ] +578 def foo x:&:num -> y:num [ +579 local-scope +580 load-ingredients +581 return 35 +582 ] +583 def! foo x:&:num -> y:num [ +584 local-scope +585 load-ingredients +586 return 36 +587 ] +588 +mem: storing 34 in location 2 +589 $error: 0 +590 +591 :(scenario dispatch_errors_come_after_unknown_name_errors) +592 % Hide_errors = true; +593 def main [ +594 y:num <- foo x +595 ] +596 def foo a:num -> b:num [ +597 local-scope +598 load-ingredients +599 return 34 +600 ] +601 def foo a:bool -> b:num [ +602 local-scope +603 load-ingredients +604 return 35 +605 ] +606 +error: main: missing type for 'x' in 'y:num <- foo x' +607 +error: main: failed to find a matching call for 'y:num <- foo x' +608 +609 :(scenario override_methods_with_type_abbreviations) +610 def main [ +611 local-scope +612 s:text <- new [abc] +613 1:num/raw <- foo s +614 ] +615 def foo a:address:array:character -> result:number [ +616 return 34 +617 ] +618 # identical to previous variant once you take type abbreviations into account +619 def! foo a:text -> result:num [ +620 return 35 +621 ] +622 +mem: storing 35 in location 1 +623 +624 :(before "End Includes") +625 using std::abs; -- cgit 1.4.1-2-gfad0