2880
Turns out we don't need a primitive to return an empty value of arbitrary type. Just create it on the heap using 'new'. But this uncovered *yet* another bug, sigh. When I specialize generic functions I was running all transforms on the generated functions after specialization completed. But there's one transform that includes code from elsewhere. If such code included type-ingredients -- kaboom. Now fixed and there's a test, so I've got that going for me which is nice.
This commit is contained in:
parent
b1ddb41400
commit
5b22547bb3
|
@ -174,7 +174,8 @@ string best_variant(instruction& inst, const recipe& caller_recipe) {
|
|||
candidates = strictly_matching_variants(inst, variants);
|
||||
if (!candidates.empty()) return best_variant(inst, candidates).name;
|
||||
|
||||
// Static Dispatch Phase 2 (shape-shifting recipes in a later layer)
|
||||
// Static Dispatch Phase 2
|
||||
//: (shape-shifting recipes in a later layer)
|
||||
// End Static Dispatch Phase 2
|
||||
|
||||
// Static Dispatch Phase 3
|
||||
|
|
|
@ -61,6 +61,8 @@ if (!candidates.empty()) {
|
|||
if (!variant.steps.empty()) {
|
||||
trace(9992, "transform") << "transforming new specialization: " << variant.name << end();
|
||||
for (int t = 0; t < SIZE(Transform); ++t) {
|
||||
// one exception: skip tangle, which would have already occurred inside new_variant above
|
||||
if (Transform.at(t) == insert_fragments) continue;
|
||||
(*Transform.at(t))(new_recipe_ordinal);
|
||||
}
|
||||
}
|
||||
|
@ -230,8 +232,14 @@ recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst, con
|
|||
recipe& new_recipe = get(Recipe, new_recipe_ordinal);
|
||||
new_recipe.name = new_name;
|
||||
trace(9993, "transform") << "switching " << inst.name << " to specialized " << header_label(new_recipe_ordinal) << end();
|
||||
// Since the exemplar never ran any transforms, we have to redo some of the
|
||||
// work of the check_types_by_name transform while supporting type-ingredients.
|
||||
|
||||
// Replace type ingredients with concrete types in new_recipe.
|
||||
//
|
||||
// preprocessing: micro-manage a couple of transforms
|
||||
// a) perform tangle *before* replacing type ingredients, just in case
|
||||
// inserted code involves type ingredients
|
||||
insert_fragments(new_recipe_ordinal);
|
||||
// b) do the work of check_types_by_name while supporting type-ingredients
|
||||
compute_type_names(new_recipe);
|
||||
// that gives enough information to replace type-ingredients with concrete types
|
||||
{
|
||||
|
@ -1027,3 +1035,21 @@ def main [
|
|||
foo *z
|
||||
]
|
||||
# shouldn't crash
|
||||
|
||||
:(scenario tangle_shape_shifting_recipe)
|
||||
# shape-shifting recipe
|
||||
def foo a:_elem [
|
||||
local-scope
|
||||
load-ingredients
|
||||
<label1>
|
||||
]
|
||||
# tangle some code that refers to the type ingredient
|
||||
after <label1> [
|
||||
b:_elem <- copy a
|
||||
]
|
||||
# trigger specialization
|
||||
def main [
|
||||
local-scope
|
||||
foo 34
|
||||
]
|
||||
$exit: 0
|
||||
|
|
|
@ -12,10 +12,11 @@ scenario channel [
|
|||
run [
|
||||
1:address:source:number, 2:address:sink:number <- new-channel 3/capacity
|
||||
2:address:sink:number <- write 2:address:sink:number, 34
|
||||
3:number, 1:address:source:number <- read 1:address:source:number
|
||||
3:number, 4:boolean, 1:address:source:number <- read 1:address:source:number
|
||||
]
|
||||
memory-should-contain [
|
||||
3 <- 34
|
||||
4 <- 0 # read was successful
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -74,7 +75,6 @@ def write out:address:sink:_elem, val:_elem -> out:address:sink:_elem [
|
|||
free:number <- get *chan, first-free:offset
|
||||
*circular-buffer <- put-index *circular-buffer, free, val
|
||||
# mark its slot as filled
|
||||
# todo: clear the slot itself
|
||||
free <- add free, 1
|
||||
{
|
||||
# wrap free around to 0 if necessary
|
||||
|
@ -87,9 +87,10 @@ def write out:address:sink:_elem, val:_elem -> out:address:sink:_elem [
|
|||
*chan <- put *chan, first-free:offset, free
|
||||
]
|
||||
|
||||
def read in:address:source:_elem -> result:_elem, in:address:source:_elem [
|
||||
def read in:address:source:_elem -> result:_elem, fail?:boolean, in:address:source:_elem [
|
||||
local-scope
|
||||
load-ingredients
|
||||
fail? <- copy 0/false # default status
|
||||
chan:address:channel:_elem <- get *in, chan:offset
|
||||
{
|
||||
# block if chan is empty
|
||||
|
@ -103,8 +104,10 @@ def read in:address:source:_elem -> result:_elem, in:address:source:_elem [
|
|||
full:number <- get *chan, first-full:offset
|
||||
circular-buffer:address:array:_elem <- get *chan, data:offset
|
||||
result <- index *circular-buffer, full
|
||||
# clear the slot
|
||||
empty:address:_elem <- new _elem:type
|
||||
*circular-buffer <- put-index *circular-buffer, full, *empty
|
||||
# mark its slot as empty
|
||||
# todo: clear the slot itself
|
||||
full <- add full, 1
|
||||
{
|
||||
# wrap full around to 0 if necessary
|
||||
|
@ -124,7 +127,7 @@ def clear in:address:source:_elem -> in:address:source:_elem [
|
|||
{
|
||||
empty?:boolean <- channel-empty? chan
|
||||
break-if empty?
|
||||
_, in <- read in
|
||||
_, _, in <- read in
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -159,7 +162,7 @@ scenario channel-read-increments-full [
|
|||
run [
|
||||
1:address:source:number, 2:address:sink:number <- new-channel 3/capacity
|
||||
2:address:sink:number <- write 2:address:sink:number, 34
|
||||
_, 1:address:source:number <- read 1:address:source:number
|
||||
_, _, 1:address:source:number <- read 1:address:source:number
|
||||
3:address:channel:number <- get *1:address:source:number, chan:offset
|
||||
4:number <- get *3:address:channel:number, first-full:offset
|
||||
5:number <- get *3:address:channel:number, first-free:offset
|
||||
|
@ -177,7 +180,7 @@ scenario channel-wrap [
|
|||
3:address:channel:number <- get *1:address:source:number, chan:offset
|
||||
# write and read a value
|
||||
2:address:sink:number <- write 2:address:sink:number, 34
|
||||
_, 1:address:source:number <- read 1:address:source:number
|
||||
_, _, 1:address:source:number <- read 1:address:source:number
|
||||
# first-free will now be 1
|
||||
4:number <- get *3:address:channel:number, first-free:offset
|
||||
5:number <- get *3:address:channel:number, first-free:offset
|
||||
|
@ -185,7 +188,7 @@ scenario channel-wrap [
|
|||
2:address:sink:number <- write 2:address:sink:number, 34
|
||||
6:number <- get *3:address:channel:number, first-free:offset
|
||||
# read second value, verify that first-full wraps
|
||||
_, 1:address:source:number <- read 1:address:source:number
|
||||
_, _, 1:address:source:number <- read 1:address:source:number
|
||||
7:number <- get *3:address:channel:number, first-full:offset
|
||||
]
|
||||
memory-should-contain [
|
||||
|
@ -242,7 +245,7 @@ scenario channel-read-not-full [
|
|||
1:address:source:number, 2:address:sink:number <- new-channel 1/capacity
|
||||
3:address:channel:number <- get *1:address:source:number, chan:offset
|
||||
2:address:sink:number <- write 2:address:sink:number, 34
|
||||
_, 1:address:source:number <- read 1:address:source:number
|
||||
_, _, 1:address:source:number <- read 1:address:source:number
|
||||
4:boolean <- channel-empty? 3:address:channel:number
|
||||
5:boolean <- channel-full? 3:address:channel:number
|
||||
]
|
||||
|
@ -288,7 +291,11 @@ after <channel-write-initial> [
|
|||
|
||||
after <channel-read-empty> [
|
||||
closed?:boolean <- get *chan, closed?:offset
|
||||
return-if closed?, 0/hack # only scalar _elems supported in channels; need to support construction of arbitrary empty containers
|
||||
{
|
||||
break-unless closed?
|
||||
empty-result:address:_elem <- new _elem:type
|
||||
return *empty-result, 1/true
|
||||
}
|
||||
]
|
||||
|
||||
## helpers
|
||||
|
@ -335,12 +342,14 @@ def buffer-lines in:address:source:character, buffered-out:address:sink:characte
|
|||
local-scope
|
||||
load-ingredients
|
||||
# repeat forever
|
||||
eof?:boolean <- copy 0/false
|
||||
{
|
||||
line:address:buffer <- new-buffer 30
|
||||
# read characters from 'in' until newline, copy into line
|
||||
{
|
||||
+next-character
|
||||
c:character, in <- read in
|
||||
c:character, eof?:boolean, in <- read in
|
||||
break-if eof?
|
||||
# drop a character on backspace
|
||||
{
|
||||
# special-case: if it's a backspace
|
||||
|
@ -361,9 +370,6 @@ def buffer-lines in:address:source:character, buffered-out:address:sink:characte
|
|||
line <- append line, c
|
||||
line-done?:boolean <- equal c, 10/newline
|
||||
break-if line-done?
|
||||
# stop buffering on eof (currently only generated by fake console)
|
||||
eof?:boolean <- equal c, 0/eof
|
||||
break-if eof?
|
||||
loop
|
||||
}
|
||||
# copy line into 'buffered-out'
|
||||
|
|
|
@ -24,7 +24,8 @@ def consumer source:address:source:character -> source:address:source:character
|
|||
load-ingredients
|
||||
{
|
||||
# read an integer from the channel
|
||||
n:character, source <- read source
|
||||
n:character, eof?:boolean, source <- read source
|
||||
break-if eof?
|
||||
# other threads might get between these prints
|
||||
$print [consume: ], n:character, [
|
||||
]
|
||||
|
|
|
@ -260,7 +260,8 @@ def read-move stdin:address:source:character, screen:address:screen -> result:ad
|
|||
def read-file stdin:address:source:character, screen:address:screen -> file:number, quit:boolean, error:boolean, stdin:address:source:character, screen:address:screen [
|
||||
local-scope
|
||||
load-ingredients
|
||||
c:character, stdin <- read stdin
|
||||
c:character, eof?:boolean, stdin <- read stdin
|
||||
return-if eof?, 0/dummy, 1/quit, 0/error
|
||||
{
|
||||
q-pressed?:boolean <- equal c, 81/Q
|
||||
break-unless q-pressed?
|
||||
|
@ -302,11 +303,12 @@ def read-file stdin:address:source:character, screen:address:screen -> file:numb
|
|||
return file, 0/quit, 0/error
|
||||
]
|
||||
|
||||
# valid values: 0-7, -1 (quit), -2 (error)
|
||||
# valid values for rank: 0-7
|
||||
def read-rank stdin:address:source:character, screen:address:screen -> rank:number, quit?:boolean, error?:boolean, stdin:address:source:character, screen:address:screen [
|
||||
local-scope
|
||||
load-ingredients
|
||||
c:character, stdin <- read stdin
|
||||
c:character, eof?:boolean, stdin <- read stdin
|
||||
return-if eof?, 0/dummy, 1/quit, 0/error
|
||||
{
|
||||
q-pressed?:boolean <- equal c, 8/Q
|
||||
break-unless q-pressed?
|
||||
|
@ -347,7 +349,8 @@ def read-rank stdin:address:source:character, screen:address:screen -> rank:numb
|
|||
def expect-from-channel stdin:address:source:character, expected:character, screen:address:screen -> result:boolean, stdin:address:source:character, screen:address:screen [
|
||||
local-scope
|
||||
load-ingredients
|
||||
c:character, stdin <- read stdin
|
||||
c:character, eof?:boolean, stdin <- read stdin
|
||||
return-if eof? 1/true
|
||||
{
|
||||
match?:boolean <- equal c, expected
|
||||
break-if match?
|
||||
|
|
Loading…
Reference in New Issue
Block a user