dsc#92: give bytes a member catalog starting at .length - #106
Merged
Conversation
`bytes` is a Uint8Array view (dsc#88): it indexes but had no member
catalog, so `bytes.length` failed check after dsc#89 closed template
interpolation. Add `("bytes", "length")` to the primitive member
table, matching the string/array property convention; emission is the
transparent field access, so the runtime cost is zero.
RFD 15 lists `len` among the bytes operations; it is surfaced as the
`.length` property rather than a `len` member no other primitive has.
The rest of the RFD 15 operations (slice, concat, hex/base64,
conversions) stay out of the catalog until deka#756 implements the RFD,
so the catalog is deliberately closed at one member and the
unknown-member diagnostic says so: `bytes` has no field `x`
(available: `length`).
This was referenced Sep 10, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes dsc#92. Tracker: dsc#66. Related: dsc#89, dsc#88, dsc#90, deka#756.
What
bytesgets a member catalog with exactly one member:.length. This is the entire change to the language surface.RFD 15 justification, member by member
RFD 15 (dekaruntime/rfd#15) specifies the bytes operations as
len,slice,concat,to_hex,from_hex,to_base64,from_base64,from_string, and a fallibleto_string. None of the operation names are specified as member-method shape — the RFD never commits to member access vs free functions, and how each lands is deka#756's call. This PR adds only what is unambiguous and provably missing:.length— added. This is RFD 15'slenoperation. It is surfaced as the.lengthproperty to match the conventionstring.lengthandarray.lengthalready establish (primitive_memberincrates/deka_syntax/src/typeck/expr.rs), not as alenmember that no other primitive has. Thebytespackage already exposes free-functionlen(tests/testsuite/packages/bytes_from_string_len), so the operation exists on both shapes the RFD's naming leaves open.slice,concat— deliberately not added. Both are in the RFD's operation list, but exposing them as members now would pre-empt deka#756's design decision (member vs free function, and forslice, whether bounds behaviour gets DekaScript semantics rather than JS's). The unknown-member diagnostic names what exists, so a user who reaches forb.slicegets`bytes` has no field `slice` (available: `length`)at check time, not a silent gap.to_hex/from_hex/to_base64/from_base64/from_string/to_string— not added. These are conversions with open design questions in the RFD itself (fallible shape:OptionvsResultis RFD 15 open question 1). Landing them here would ship ahead of the design; that is deka#756.Nothing here contradicts or exceeds RFD 15: the one member added is the one operation the RFD guarantees, under the spelling the rest of the language's primitives use.
The catalog is closed
resolve_primitive_fieldgains a dedicatedbytesarm, so a nonexistent member is a check-time error with a span and a message naming the one available member (theJsErrordiagnostic pattern). Unit tests pin both directions:bytes.lengthis anumberproperty (and rejects flow intostring), andb.sliceerrors at line 2, column 10. Indexing (b[0], dsc#88) is untouched.Emission cost: zero
bytesis aUint8Arrayat runtime and the emitter'sFieldAccessarm is transparent, sov.lengthcompiles to exactlyv.length— what you would hand-write. A transpile test (bytes_length_transpiles_verbatimincrates/cli/tests/transpile.rs) pins that: the emitted JS containsb.lengthand no__dekahelper.Fixtures
tests/testsuite/data_types/bytes_length— executed (stagerun), exact stdout3:65:67, exercising the dsc#89 regression case directly:${v.length}inside template interpolation on a narrowedbytes.tests/testsuite/types/bytes_unknown_member— negative fixture, unknown member rejected with the expected diagnostic.scripts/dsc-versionpin past it, the two ratcheted lines in deka'sexpected-failures.txt(unsafe-textencoder-encode,unsafe-uint8array-literal) can come out per their stated removal condition.Test output
cargo test --workspace— all suites green (incl. the two new checker tests and the new transpile test; the only warnings are two pre-existing unused-variable ones also present onmain).Testsuite against the pinned runtime (0.46.0) plus this branch's dsc:
Both new fixtures verified individually:
bytes_lengthpasses at stagerunwith stdout3:65:67;bytes_unknown_memberfails check with[transpile] 2:10:byteshas no fieldslice(available:length).-kimi