From 6f654bafecc95ba0b5d20e823459d3115c5a3dec Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 5 Feb 2026 12:54:21 -0600 Subject: [PATCH] Change validation to reject stream (for now) --- design/mvp/Binary.md | 2 ++ design/mvp/CanonicalABI.md | 5 ++++- design/mvp/Concurrency.md | 4 ++-- design/mvp/Explainer.md | 3 +++ design/mvp/canonical-abi/definitions.py | 1 + 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/design/mvp/Binary.md b/design/mvp/Binary.md index 03812964..3a2fa83b 100644 --- a/design/mvp/Binary.md +++ b/design/mvp/Binary.md @@ -253,6 +253,8 @@ Notes: rejects any transitive use of `borrow` in an exported value type. * Validation of `stream` and `future` rejects element types that transitively contain a `borrow`. +* Validation of `stream` rejects `(stream char)` as a temporary + [TODO](Concurrency.md#TODO). * Validation of `resourcetype` requires the destructor (if present) to have type `[i32] -> []`. * Validation of `instancedecl` (currently) only allows the `type` and diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 133cd3f1..cf1e8fb3 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -4212,8 +4212,11 @@ Then a readable or writable buffer is created which (in `Buffer`'s constructor) eagerly checks the alignment and bounds of (`i`, `n`). (In the future, the restriction on futures/streams containing `borrow`s could be relaxed by maintaining sufficient bookkeeping state to ensure that borrowed handles *or -streams/futures of borrowed handles* could not outlive their originating call.) +streams/futures of borrowed handles* could not outlive their originating call. +Additionally, `stream` will be allowed and defined to encode and decode +according to the `string-encoding`.) ```python + assert(not isinstance(stream_t, CharType)) assert(not contains_borrow(stream_t)) cx = LiftLowerContext(opts, thread.task.inst, borrow_scope = None) buffer = BufferT(stream_t.t, cx, ptr, n) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index 0ec5972b..6c9c5f6f 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -1259,6 +1259,8 @@ comes after: * remove the temporary trap mentioned above that occurs when a `read` and `write` of a stream/future happen from within the same component instance * zero-copy forwarding/splicing +* allow the `stream` type to validate; make it use `string-encoding` + and not split code points * some way to say "no more elements are coming for a while" * add an `async` effect on `component` type definitions allowing a component type to block during instantiation @@ -1270,8 +1272,6 @@ comes after: * add a `strict-callback` option that adds extra trapping conditions to provide the semantic guarantees needed for engines to statically avoid fiber creation at component-to-component `async` call boundaries -* add `stringstream` specialization of `stream` (just like `string` is - a specialization of `list`) * allow pipelining multiple `stream.read`/`write` calls * allow chaining multiple async calls together ("promise pipelining") * integrate with `shared`: define how to lift and lower functions `async` *and* diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md index e21553fb..d3e31d59 100644 --- a/design/mvp/Explainer.md +++ b/design/mvp/Explainer.md @@ -753,6 +753,9 @@ empty futures and streams can be useful for timing-related APIs. Currently, validation rejects `(stream T)` and `(future T)` when `T` transitively contains a `borrow`. This restriction could be relaxed in the future by extending the call-scoping rules of `borrow` to streams and futures. +Additionally, `(stream char)` is temporarily rejected with a future +[TODO](Concurrency.md) to allow and properly use the `string-encoding`, +taking care to not split code points. #### Specialized value types diff --git a/design/mvp/canonical-abi/definitions.py b/design/mvp/canonical-abi/definitions.py index 4a36c572..32db6db0 100644 --- a/design/mvp/canonical-abi/definitions.py +++ b/design/mvp/canonical-abi/definitions.py @@ -2362,6 +2362,7 @@ def stream_copy(EndT, BufferT, event_code, stream_t, opts, thread, i, ptr, n): trap_if(e.shared.t != stream_t.t) trap_if(e.state != CopyState.IDLE) + assert(not isinstance(stream_t, CharType)) assert(not contains_borrow(stream_t)) cx = LiftLowerContext(opts, thread.task.inst, borrow_scope = None) buffer = BufferT(stream_t.t, cx, ptr, n)