Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions bend2/comp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,16 @@ const BOX: Lay = { ks: ["box"], arms: null };

const W64: Lay = { ks: ["w64"], arms: null };

const WORDS: Record<string, Lay> = { U32: W32, F32: W32, Nat: W64 };
// A datatype's name indexes this table, so it has a null prototype:
// `__proto__` or `toString` would otherwise inherit a value that is not
// a Lay, like OPERATIONS and OPTIMIZED below.
const WORDS: Record<string, Lay> = Object.setPrototypeOf(
{ U32: W32, F32: W32, Nat: W64 }, null);

// The printed cell kind of a datatype the runtime knows, 7 for any
// other: a datatype's name indexes it, so it is null-prototyped too.
const SHOWN: Record<string, number> = Object.setPrototypeOf(
{ U32: 0, F32: 1, Nat: 2, Char: 3, String: 4, Array: 6 }, null);

// The widest flat datatype: the shader's Tri is 24 words.
const WIDE = 256;
Expand Down Expand Up @@ -1301,8 +1310,7 @@ function show_main(book: Bend.Book): Show | null {
if (adt === null || adt.k === "IO.OP" || tld?.$ !== "ADT") {
return refuse();
}
const kind = { U32: 0, F32: 1, Nat: 2, Char: 3, String: 4, Array: 6 }[adt.k]
?? 7;
const kind = SHOWN[adt.k] ?? 7;
const id = show.cells.push(kind) - 1;
ids.set(key, id);
const refs: [number, HTerm, Lay][] = [];
Expand Down
27 changes: 27 additions & 0 deletions tests/compile/proto_name_array_cell.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# an Array whose element datatype is named after an Object.prototype
# member: the cell's layout is read through the same name-indexed table
# by lay_el, which died in lay.ks.some rather than lay.ks.length. The
# array must reach the printed result: reading one element alone walks
# no layout and compiles on base
import Base

type toString is Data:
E{v: U32}

law main.head:
for a: Array<toString>
U32

def main.head(a):
match a:
case ALeaf{item}:
match item:
case E{v}:
v
case ANode{left, right}:
0

def main() -> Array<toString> & U32:
([E{4} : toString*1n], main.head([E{7} : toString*1n]))

#|([E{4}], 7)
23 changes: 23 additions & 0 deletions tests/compile/proto_name_ctor_field.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# (control) a CONSTRUCTOR and a FIELD named after an Object.prototype
# member compile on base too: only a DATATYPE's name indexes WORDS and
# the printed-kind table, and a constructor's own emitted key is already
# a computed property. This pins the fix's scope -- it must not need to
# change, and must not break, the constructor and field name paths
import Base

type Box is Data:
__proto__{toString: U32}

law main.out:
for b: Box
U32

def main.out(b):
match b:
case __proto__{toString}:
toString

def main() -> Box & U32:
(__proto__{5}, main.out(__proto__{5}))

#|(__proto__{5}, 5)
41 changes: 41 additions & 0 deletions tests/compile/proto_name_datatype.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# a datatype named after an Object.prototype member is an ordinary
# datatype: the compiler's name-indexed tables must not answer an
# inherited member for it. WORDS gave __proto__ the prototype object
# instead of undefined, so lay_of returned a non-Lay and both emitters
# died in lay.ks.length; the printed-kind table gave toString a
# function, which left the emitted show descriptor holding no cells
import Base

type __proto__ is Data:
P{v: U32}

type constructor is Data:
C{p: __proto__}

type toString is Data:
T{c: constructor, w: U32}

law main.wrap:
for n: U32
toString

def main.wrap(n):
T{C{P{n}}, 7}

law main.out:
for t: toString
U32

def main.out(t):
match t:
case T{c, w}:
match c:
case C{p}:
match p:
case P{v}:
(v + w : U32)

def main() -> toString & U32:
(main.wrap(35), main.out(main.wrap(35)))

#|(T{C{P{35}}, 7}, 42)
21 changes: 21 additions & 0 deletions tests/compile/proto_name_type_param.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# a parametrized datatype named after an Object.prototype member: its
# name reaches the same name-indexed tables through the type argument,
# so it broke where the flat case did (lay_of -> lay.ks.length)
import Base

type __proto__<A: Data> is Data:
W{item: A}

law main.out:
for w: __proto__<U32>
U32

def main.out(w):
match w:
case W{item}:
item

def main() -> __proto__<U32> & U32:
(W{9}, main.out(W{9}))

#|(W{9}, 9)
33 changes: 33 additions & 0 deletions tests/compile/proto_name_value_of.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# the Object.prototype members the issue does not name reach the same
# name-indexed tables: valueOf and hasOwnProperty inherit FUNCTIONS and
# propertyIsEnumerable one more, so the lookup is never undefined for
# them either. One nesting per name, so a table that answered only the
# three reported names would still die here
import Base

type valueOf is Data:
V{n: U32}

type hasOwnProperty is Data:
H{v: valueOf}

type propertyIsEnumerable is Data:
Q{h: hasOwnProperty, m: U32}

law main.out:
for q: propertyIsEnumerable
U32

def main.out(q):
match q:
case Q{h, m}:
match h:
case H{v}:
match v:
case V{n}:
(n + m : U32)

def main() -> propertyIsEnumerable & U32:
(Q{H{V{20}}, 22}, main.out(Q{H{V{20}}, 22}))

#|(Q{H{V{20}}, 22}, 42)