Add remaining tests specific to DisposableStack

This commit is contained in:
Ron Buckton 2025-05-12 11:39:06 -04:00 committed by Jordan Harband
parent c2e3e37b68
commit fe1c065cbb
39 changed files with 1554 additions and 0 deletions

View File

@ -0,0 +1,23 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype-@@toStringTag
description: >
`Symbol.toStringTag` property descriptor
info: |
The initial value of the @@toStringTag property is the String value
'DisposableStack'.
This property has the attributes { [[Writable]]: false, [[Enumerable]]:
false, [[Configurable]]: true }.
includes: [propertyHelper.js]
features: [explicit-resource-management, Symbol, Symbol.toStringTag]
---*/
verifyProperty(DisposableStack.prototype, Symbol.toStringTag, {
value: 'DisposableStack',
writable: false,
enumerable: false,
configurable: true
});

View File

@ -0,0 +1,37 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.adopt
description: Adds a disposable resource to the stack
info: |
DisposableStack.prototype.adopt ( value, onDispose )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. If IsCallable(onDispose) is false, throw a TypeError exception.
5. Let closure be a new Abstract Closure with no parameters that captures value and onDispose and performs the following steps when called:
a. Perform ? Call(onDispose, undefined, « value »).
6. Let F be CreateBuiltinFunction(closure, 0, "", « »).
7. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, F).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
...
2. Else,
a. Assert: V is undefined.
b. Let resource be ? CreateDisposableResource(undefined, hint, method).
3. Append resource to disposeCapability.[[DisposableResourceStack]].
4. Return unused.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var resource = { disposed: false };
stack.adopt(resource, r => { r.disposed = true });
stack.dispose();
assert.sameValue(resource.disposed, true, 'Expected resource to have been disposed');

View File

@ -0,0 +1,33 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.adopt
description: Allows any 'value'
info: |
DisposableStack.prototype.adopt ( value, onDispose )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. If IsCallable(onDispose) is false, throw a TypeError exception.
5. Let closure be a new Abstract Closure with no parameters that captures value and onDispose and performs the following steps when called:
a. Perform ? Call(onDispose, undefined, « value »).
6. Let F be CreateBuiltinFunction(closure, 0, "", « »).
7. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, F).
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
stack.adopt(null, _ => {});
stack.adopt(undefined, _ => {});
stack.adopt({}, _ => {});
stack.adopt({ [Symbol.dispose]() {} }, _ => {});
stack.adopt(() => {}, _ => {});
stack.adopt(true, _ => {});
stack.adopt(false, _ => {});
stack.adopt(1, _ => {});
stack.adopt('object', _ => {});
stack.adopt(Symbol(), _ => {});

View File

@ -0,0 +1,46 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.adopt
description: Adds a disposable resource to the stack
info: |
DisposableStack.prototype.adopt ( value, onDispose )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. If IsCallable(onDispose) is false, throw a TypeError exception.
5. Let closure be a new Abstract Closure with no parameters that captures value and onDispose and performs the following steps when called:
a. Perform ? Call(onDispose, undefined, « value »).
6. Let F be CreateBuiltinFunction(closure, 0, "", « »).
7. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, F).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
...
2. Else,
a. Assert: V is undefined.
b. Let resource be ? CreateDisposableResource(undefined, hint, method).
3. Append resource to disposeCapability.[[DisposableResourceStack]].
4. Return unused.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var disposed = [];
var resource1 = {};
function dispose1(res) { disposed.push([res, dispose1]); }
var resource2 = {};
function dispose2(res) { disposed.push([res, dispose2]); }
stack.adopt(resource1, dispose1);
stack.adopt(resource2, dispose2);
stack.dispose();
assert.sameValue(2, disposed.length);
assert.sameValue(disposed[0][0], resource2, 'Expected resource2 to be the first disposed resource');
assert.sameValue(disposed[0][1], dispose2, 'Expected dispose2 to be the first onDispose invoked');
assert.sameValue(disposed[1][0], resource1, 'Expected resource1 to be the second disposed resource');
assert.sameValue(disposed[1][1], dispose1, 'Expected dispose1 to be the second onDispose invoked');

View File

@ -0,0 +1,20 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.adopt
description: Returns the argument provided.
info: |
DisposableStack.prototype.adopt ( value, onDispose )
...
8. Return value.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var resource = {};
assert.sameValue(stack.adopt(resource, _ => {}), resource);
assert.sameValue(stack.adopt(null, _ => {}), null);
assert.sameValue(stack.adopt(undefined, _ => {}), undefined);

View File

@ -0,0 +1,49 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.adopt
description: Throws if onDispose argument not callable
info: |
DisposableStack.prototype.adopt ( value, onDispose )
...
4. If IsCallable(onDispose) is false, throw a TypeError exception.
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.throws(TypeError, function() {
stack.adopt(null, null);
}, 'null');
assert.throws(TypeError, function() {
stack.adopt(null, undefined);
}, 'undefined');
assert.throws(TypeError, function() {
stack.adopt(null, true);
}, 'true');
assert.throws(TypeError, function() {
stack.adopt(null, false);
}, 'false');
assert.throws(TypeError, function() {
stack.adopt(null, 1);
}, 'number');
assert.throws(TypeError, function() {
stack.adopt(null, 'object');
}, 'string');
assert.throws(TypeError, function() {
stack.adopt(null, {});
}, 'object');
var s = Symbol();
assert.throws(TypeError, function() {
stack.adopt(null, s);
}, 'symbol');

View File

@ -0,0 +1,31 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-disposablestack-prototype-object
description: DisposableStack.prototype.constructor
info: |
DisposableStack.prototype.constructor
Normative Optional
The initial value of DisposableStack.prototype.constructor is the intrinsic object %DisposableStack%.
This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
This section is to be treated identically to the "Annex B" of ECMA-262, but to be written in-line with the main specification.
includes: [propertyHelper.js]
features: [explicit-resource-management]
---*/
var actual = DisposableStack.prototype.hasOwnProperty('constructor');
// If implemented, it should conform to the spec text
if (actual) {
verifyProperty(DisposableStack.prototype, 'constructor', {
value: DisposableStack,
writable: true,
enumerable: false,
configurable: true
});
}

View File

@ -0,0 +1,34 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.defer
description: Adds an onDispose callback to the stack
info: |
DisposableStack.prototype.defer ( onDispose )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. If IsCallable(onDispose) is false, throw a TypeError exception.
5. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, onDispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
...
2. Else,
a. Assert: V is undefined.
b. Let resource be ? CreateDisposableResource(undefined, hint, method).
3. Append resource to disposeCapability.[[DisposableResourceStack]].
4. Return unused.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var disposed = false;
stack.defer(() => { disposed = true });
stack.dispose();
assert.sameValue(disposed, true, 'Expected callback to have been called');

View File

@ -0,0 +1,39 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.defer
description: Adds a disposable resource to the stack
info: |
DisposableStack.prototype.defer ( onDispose )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. If IsCallable(onDispose) is false, throw a TypeError exception.
5. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, onDispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
...
2. Else,
a. Assert: V is undefined.
b. Let resource be ? CreateDisposableResource(undefined, hint, method).
3. Append resource to disposeCapability.[[DisposableResourceStack]].
4. Return unused.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var disposed = [];
function dispose1() { disposed.push(dispose1); }
function dispose2() { disposed.push(dispose2); }
stack.defer(dispose1);
stack.defer(dispose2);
stack.dispose();
assert.sameValue(2, disposed.length);
assert.sameValue(disposed[0], dispose2, 'Expected dispose2 to be the first onDispose invoked');
assert.sameValue(disposed[1], dispose1, 'Expected dispose1 to be the second onDispose invoked');

View File

@ -0,0 +1,17 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.defer
description: Returns the argument provided.
info: |
DisposableStack.prototype.defer ( onDispose )
...
6. Return undefined.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.sameValue(stack.defer(_ => {}), undefined);

View File

@ -0,0 +1,49 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.defer
description: Adds a callback to the stack
info: |
DisposableStack.prototype.defer ( onDispose )
...
4. If IsCallable(onDispose) is false, throw a TypeError exception.
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.throws(TypeError, function() {
stack.defer(null);
}, 'null');
assert.throws(TypeError, function() {
stack.defer(undefined);
}, 'undefined');
assert.throws(TypeError, function() {
stack.defer(true);
}, 'true');
assert.throws(TypeError, function() {
stack.defer(false);
}, 'false');
assert.throws(TypeError, function() {
stack.defer(1);
}, 'number');
assert.throws(TypeError, function() {
stack.defer('object');
}, 'string');
assert.throws(TypeError, function() {
stack.defer({});
}, 'object');
var s = Symbol();
assert.throws(TypeError, function() {
stack.defer(s);
}, 'symbol');

View File

@ -0,0 +1,69 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.dispose
description: Added resources are disposed in reverse order
info: |
UsingDeclaration : using BindingList ;
1. Perform ? BindingEvaluation of BindingList with argument sync-dispose.
2. Return empty.
BindingList : BindingList , LexicalBinding
1. Perform ? BindingEvaluation of BindingList with argument hint.
2. Perform ? BindingEvaluation of LexicalBinding with argument hint.
3. Return unused.
LexicalBinding : BindingIdentifier Initializer
1. Let bindingId be StringValue of BindingIdentifier.
2. Let lhs be ? ResolveBinding(bindingId).
3. If IsAnonymousFunctionDefinition(Initializer) is true, then
a. Let value be NamedEvaluation of Initializer with argument bindingId.
4. Else,
a. Let rhs be the result of evaluating Initializer.
b. Let value be ? GetValue(rhs).
5. Return ? InitializeReferencedBinding(lhs, value, hint).
DisposeResources ( disposeCapability, completion )
1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do
a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
b. If result.[[Type]] is throw, then
i. If completion.[[Type]] is throw, then
1. Set result to result.[[Value]].
2. Let suppressed be completion.[[Value]].
3. Let error be a newly created SuppressedError object.
4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed).
6. Set completion to ThrowCompletion(error).
ii. Else,
1. Set completion to result.
2. Return completion.
Dispose ( V, hint, method )
1. If method is undefined, let result be undefined.
2. Else, let result be ? Call(method, V).
3. If hint is async-dispose, then
a. Perform ? Await(result).
4. Return undefined.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var disposed = [];
var resource1 = { [Symbol.dispose]() { disposed.push(resource1); } };
var resource2 = {};
function dispose2(res) { disposed.push(res); }
function dispose3() { disposed.push(dispose3); }
stack.use(resource1);
stack.adopt(resource2, dispose2);
stack.defer(dispose3);
stack.dispose();
assert.sameValue(disposed[0], dispose3);
assert.sameValue(disposed[1], resource2);
assert.sameValue(disposed[2], resource1);

View File

@ -0,0 +1,54 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.dispose
description: Does not re-invoke disposal on resources after stack has already been disposed.
info: |
DisposableStack.prototype.dispose ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, return undefined.
4. Set disposableStack.[[DisposableState]] to disposed.
5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)).
DisposeResources ( disposeCapability, completion )
1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do
a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
b. If result.[[Type]] is throw, then
i. If completion.[[Type]] is throw, then
1. Set result to result.[[Value]].
2. Let suppressed be completion.[[Value]].
3. Let error be a newly created SuppressedError object.
4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed).
6. Set completion to ThrowCompletion(error).
ii. Else,
1. Set completion to result.
2. Return completion.
Dispose ( V, hint, method )
1. If method is undefined, let result be undefined.
2. Else, let result be ? Call(method, V).
3. If hint is async-dispose, then
a. Perform ? Await(result).
4. Return undefined.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var useCount = 0;
var adoptCount = 0;
var deferCount = 0;
stack.use({ [Symbol.dispose]() { useCount++; } });
stack.adopt({}, _ => { adoptCount++; });
stack.defer(() => { deferCount++; });
stack.dispose();
stack.dispose();
assert.sameValue(useCount, 1);
assert.sameValue(adoptCount, 1);
assert.sameValue(deferCount, 1);

View File

@ -0,0 +1,45 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.dispose
description: Does not throw if already disposed.
info: |
DisposableStack.prototype.dispose ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, return undefined.
4. Set disposableStack.[[DisposableState]] to disposed.
5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)).
DisposeResources ( disposeCapability, completion )
1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do
a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
b. If result.[[Type]] is throw, then
i. If completion.[[Type]] is throw, then
1. Set result to result.[[Value]].
2. Let suppressed be completion.[[Value]].
3. Let error be a newly created SuppressedError object.
4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed).
6. Set completion to ThrowCompletion(error).
ii. Else,
1. Set completion to result.
2. Return completion.
Dispose ( V, hint, method )
1. If method is undefined, let result be undefined.
2. Else, let result be ? Call(method, V).
3. If hint is async-dispose, then
a. Perform ? Await(result).
4. Return undefined.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
stack.dispose();
stack.dispose();

View File

@ -0,0 +1,44 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.dispose
description: Return value of dispose is undefined
info: |
DisposableStack.prototype.dispose ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, return undefined.
4. Set disposableStack.[[DisposableState]] to disposed.
5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)).
DisposeResources ( disposeCapability, completion )
1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do
a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
b. If result.[[Type]] is throw, then
i. If completion.[[Type]] is throw, then
1. Set result to result.[[Value]].
2. Let suppressed be completion.[[Value]].
3. Let error be a newly created SuppressedError object.
4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed).
6. Set completion to ThrowCompletion(error).
ii. Else,
1. Set completion to result.
2. Return completion.
Dispose ( V, hint, method )
1. If method is undefined, let result be undefined.
2. Else, let result be ? Call(method, V).
3. If hint is async-dispose, then
a. Perform ? Await(result).
4. Return undefined.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.sameValue(stack.dispose(), undefined);

View File

@ -0,0 +1,48 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.dispose
description: Sets the [[DisposableState]] internal slot to disposed
info: |
DisposableStack.prototype.dispose ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, return undefined.
4. Set disposableStack.[[DisposableState]] to disposed.
5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)).
DisposeResources ( disposeCapability, completion )
1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do
a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
b. If result.[[Type]] is throw, then
i. If completion.[[Type]] is throw, then
1. Set result to result.[[Value]].
2. Let suppressed be completion.[[Value]].
3. Let error be a newly created SuppressedError object.
4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed).
6. Set completion to ThrowCompletion(error).
ii. Else,
1. Set completion to result.
2. Return completion.
Dispose ( V, hint, method )
1. If method is undefined, let result be undefined.
2. Else, let result be ? Call(method, V).
3. If hint is async-dispose, then
a. Perform ? Await(result).
4. Return undefined.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var wasDisposed = stack.disposed;
stack.dispose();
var isDisposed = stack.disposed;
assert.sameValue(wasDisposed, false);
assert.sameValue(isDisposed, true);

View File

@ -0,0 +1,49 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.dispose
description: Rethrows an error from a disposal as-is if it is the only error.
info: |
DisposableStack.prototype.dispose ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, return undefined.
4. Set disposableStack.[[DisposableState]] to disposed.
5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)).
DisposeResources ( disposeCapability, completion )
1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do
a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
b. If result.[[Type]] is throw, then
i. If completion.[[Type]] is throw, then
1. Set result to result.[[Value]].
2. Let suppressed be completion.[[Value]].
3. Let error be a newly created SuppressedError object.
4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed).
6. Set completion to ThrowCompletion(error).
ii. Else,
1. Set completion to result.
2. Return completion.
Dispose ( V, hint, method )
1. If method is undefined, let result be undefined.
2. Else, let result be ? Call(method, V).
3. If hint is async-dispose, then
a. Perform ? Await(result).
4. Return undefined.
features: [explicit-resource-management]
---*/
class MyError extends Error {}
var stack = new DisposableStack();
stack.defer(function () { throw new MyError(); });
stack.defer(function () {});
assert.throws(MyError, function () {
stack.dispose();
});

View File

@ -0,0 +1,61 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.dispose
description: Throws multiple errors from a disposal nested in one or more SuppressedError instances.
info: |
DisposableStack.prototype.dispose ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, return undefined.
4. Set disposableStack.[[DisposableState]] to disposed.
5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)).
DisposeResources ( disposeCapability, completion )
1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do
a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
b. If result.[[Type]] is throw, then
i. If completion.[[Type]] is throw, then
1. Set result to result.[[Value]].
2. Let suppressed be completion.[[Value]].
3. Let error be a newly created SuppressedError object.
4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed).
6. Set completion to ThrowCompletion(error).
ii. Else,
1. Set completion to result.
2. Return completion.
Dispose ( V, hint, method )
1. If method is undefined, let result be undefined.
2. Else, let result be ? Call(method, V).
3. If hint is async-dispose, then
a. Perform ? Await(result).
4. Return undefined.
features: [explicit-resource-management]
---*/
class MyError extends Error {}
var error1 = new MyError();
var error2 = new MyError();
var error3 = new MyError();
var stack = new DisposableStack();
stack.defer(function () { throw error1; });
stack.defer(function () { throw error2; });
stack.defer(function () { throw error3; });
try {
stack.dispose();
assert(false, 'Expected stack.dispose() to have thrown an error.');
}
catch (e) {
assert(e instanceof SuppressedError, "Expected stack.dispose() to have thrown a SuppressedError");
assert.sameValue(e.error, error1, "Expected the outermost suppressing error to have been 'error1'");
assert(e.suppressed instanceof SuppressedError, "Expected the outermost suppressed error to have been a SuppressedError");
assert.sameValue(e.suppressed.error, error2, "Expected the innermost suppressing error to have been 'error2'");
assert.sameValue(e.suppressed.suppressed, error3, "Expected the innermost suppressed error to have been 'error3'");
}

View File

@ -0,0 +1,19 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-get-disposablestack.prototype.disposed
description: >
Returns `false` when the DisposableStack has not yet been disposed.
info: |
get DisposableStack.prototype.disposed
...
3. If disposableStack.[[DisposableState]] is disposed, return true.
4. Otherwise, return false.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.sameValue(stack.disposed, false);

View File

@ -0,0 +1,19 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-get-disposablestack.prototype.disposed
description: >
Returns `true` after the DisposableStack has been disposed.
info: |
get DisposableStack.prototype.disposed
...
3. If disposableStack.[[DisposableState]] is disposed, return true.
4. Otherwise, return false.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
stack.dispose();
assert.sameValue(stack.disposed, true);

View File

@ -0,0 +1,27 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.move
description: Resources in the stack are not disposed when move is called.
info: |
DisposableStack.prototype.move ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »).
5. Set newDisposableStack.[[DisposableState]] to pending.
6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]].
7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability().
8. Set disposableStack.[[DisposableState]] to disposed.
9. Return newDisposableStack.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var disposed = false;
stack.defer(() => { disposed = true; });
stack.move();
assert.sameValue(disposed, false);

View File

@ -0,0 +1,36 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.move
description: Returns a new DisposableStack that contains the resources originally contained in this stack.
info: |
DisposableStack.prototype.move ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »).
5. Set newDisposableStack.[[DisposableState]] to pending.
6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]].
7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability().
8. Set disposableStack.[[DisposableState]] to disposed.
9. Return newDisposableStack.
includes: [deepEqual.js]
features: [explicit-resource-management]
---*/
var stack1 = new DisposableStack();
var disposed = [];
stack1.defer(() => { disposed.push(1); });
stack1.defer(() => { disposed.push(2); });
var stack2 = stack1.move();
var wasDisposed = disposed.slice();
stack2.dispose();
var isDisposed = disposed.slice();
assert.deepEqual(wasDisposed, []);
assert.deepEqual(isDisposed, [2, 1]);

View File

@ -0,0 +1,25 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.move
description: Returns a new DisposableStack that is still pending
info: |
DisposableStack.prototype.move ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »).
5. Set newDisposableStack.[[DisposableState]] to pending.
6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]].
7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability().
8. Set disposableStack.[[DisposableState]] to disposed.
9. Return newDisposableStack.
features: [explicit-resource-management]
---*/
var stack1 = new DisposableStack();
var stack2 = stack1.move();
assert.sameValue(stack2.disposed, false);

View File

@ -0,0 +1,26 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.move
description: Returns a new DisposableStack
info: |
DisposableStack.prototype.move ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »).
5. Set newDisposableStack.[[DisposableState]] to pending.
6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]].
7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability().
8. Set disposableStack.[[DisposableState]] to disposed.
9. Return newDisposableStack.
features: [explicit-resource-management]
---*/
var stack1 = new DisposableStack();
var stack2 = stack1.move();
assert(stack2 !== stack1, 'Expected stack2 to not be the same reference as stack1');
assert(stack2 instanceof DisposableStack, 'Expected stack2 to be an instance of DisposableStack');

View File

@ -0,0 +1,28 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.move
description: The stack's [[DisposableState]] internal slot is set to disposed.
info: |
DisposableStack.prototype.move ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »).
5. Set newDisposableStack.[[DisposableState]] to pending.
6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]].
7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability().
8. Set disposableStack.[[DisposableState]] to disposed.
9. Return newDisposableStack.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var wasDisposed = stack.disposed;
stack.move();
var isDisposed = stack.disposed;
assert.sameValue(wasDisposed, false);
assert.sameValue(isDisposed, true);

View File

@ -0,0 +1,28 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.move
description: Returns a new %DisposableStack%, even when subclassed
info: |
DisposableStack.prototype.move ( )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »).
5. Set newDisposableStack.[[DisposableState]] to pending.
6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]].
7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability().
8. Set disposableStack.[[DisposableState]] to disposed.
9. Return newDisposableStack.
features: [explicit-resource-management]
---*/
class MyDisposableStack extends DisposableStack {}
var stack1 = new MyDisposableStack();
var stack2 = stack1.move();
assert(stack2 instanceof DisposableStack, 'Expected stack2 to be an instance of DisposableStack');
assert(!(stack2 instanceof MyDisposableStack), 'Expected stack2 to not be an instance of MyDisposableStack');

View File

@ -0,0 +1,23 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.move
description: Throws a ReferenceError if this is disposed.
info: |
DisposableStack.prototype.move ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
stack.dispose();
assert.throws(ReferenceError, function() {
stack.move();
}, 'undefined');

View File

@ -0,0 +1,43 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Invokes [Symbol.dispose] getter
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
2. Else,
...
3. Append resource to disposeCapability.[[DisposableResourceStack]].
4. Return unused.
features: [explicit-resource-management]
---*/
var resource = {
disposed: false,
get [Symbol.dispose]() {
return function() {
this.disposed = true;
};
}
};
var stack = new DisposableStack();
stack.use(resource);
stack.dispose();
assert.sameValue(resource.disposed, true, 'Expected resource to have been disposed');

View File

@ -0,0 +1,39 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Adds a disposable resource to the stack
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
2. Else,
...
3. Append resource to disposeCapability.[[DisposableResourceStack]].
4. Return unused.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var resource = {
disposed: false,
[Symbol.dispose]() {
this.disposed = true;
}
};
stack.use(resource);
stack.dispose();
assert.sameValue(resource.disposed, true, 'Expected resource to have been disposed');

View File

@ -0,0 +1,28 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Does not throw when argument is 'null'
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
...
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
stack.use(null);

View File

@ -0,0 +1,28 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Does not throw when argument is 'undefined'
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
...
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
stack.use(undefined);

View File

@ -0,0 +1,61 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Only reads `[Symbol.dispose]` method once, when added.
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
...
CreateDisposableResource ( V, hint [ , method ] )
1. If method is not present, then
a. If V is either null or undefined, then
i. Set V to undefined
ii. Set method to undefined
b. Else,
i. If Type(V) is not Object, throw a TypeError exception.
ii. Set method to ? GetDisposeMethod(V, hint).
iii. If method is undefined, throw a TypeError exception.
2. Else,
a. ...
3. Return the DisposableResource Record { [[ResourceValue]]: V, [[Hint]]: hint, [[DisposeMethod]]: method }.
GetDisposeMethod ( V, hint )
1. If hint is async-dispose, then
a. Let method be ? GetMethod(V, @@asyncDispose).
b. If method is undefined, then
i. Set method to ? GetMethod(V, @@dispose).
2. Else,
a. Let method be ? GetMethod(V, @@dispose).
3. Return method.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var resource = {
disposeReadCount: 0,
get [Symbol.dispose]() {
this.disposeReadCount++;
return function() { };
}
};
stack.use(resource);
stack.dispose();
assert.sameValue(resource.disposeReadCount, 1, 'Expected [Symbol.dispose] to have been read only once');

View File

@ -0,0 +1,47 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Puts value on the top of the dispose stack
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
2. Else,
...
3. Append resource to disposeCapability.[[DisposableResourceStack]].
4. Return unused.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var disposed = [];
var resource1 = {
[Symbol.dispose]() {
disposed.push(this);
}
};
var resource2 = {
[Symbol.dispose]() {
disposed.push(this);
}
};
stack.use(resource1);
stack.use(resource2);
stack.dispose();
assert.sameValue(2, disposed.length);
assert.sameValue(disposed[0], resource2, 'Expected resource2 to be the first disposed resource');
assert.sameValue(disposed[1], resource1, 'Expected resource1 to be the second disposed resource');

View File

@ -0,0 +1,20 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Returns the argument provided.
info: |
DisposableStack.prototype.use ( value )
...
5. Return value.
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
var resource = { [Symbol.dispose]() { } };
assert.sameValue(stack.use(resource), resource);
assert.sameValue(stack.use(null), null);
assert.sameValue(stack.use(undefined), undefined);

View File

@ -0,0 +1,56 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Throws a ReferenceError if this is disposed.
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
stack.dispose();
assert.throws(ReferenceError, function() {
stack.use(undefined);
}, 'undefined');
assert.throws(ReferenceError, function() {
stack.use(null);
}, 'null');
assert.throws(ReferenceError, function() {
stack.use(true);
}, 'true');
assert.throws(ReferenceError, function() {
stack.use(false);
}, 'false');
assert.throws(ReferenceError, function() {
stack.use(1);
}, 'number');
assert.throws(ReferenceError, function() {
stack.use('object');
}, 'string');
var s = Symbol();
assert.throws(ReferenceError, function() {
stack.use(s);
}, 'symbol');
assert.throws(ReferenceError, function() {
stack.use({});
}, 'non disposable object');
assert.throws(ReferenceError, function() {
stack.use({ [Symbol.dispose]() {} });
}, 'disposable object');

View File

@ -0,0 +1,58 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Throws if the argument has a null-valued Symbol.dispose property.
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
...
CreateDisposableResource ( V, hint [ , method ] )
1. If method is not present, then
a. If V is either null or undefined, then
i. Set V to undefined
ii. Set method to undefined
b. Else,
i. If Type(V) is not Object, throw a TypeError exception.
ii. Set method to ? GetDisposeMethod(V, hint).
iii. If method is undefined, throw a TypeError exception.
...
GetDisposeMethod ( V, hint )
1. If hint is async-dispose, then
a. Let method be ? GetMethod(V, @@asyncDispose).
b. If method is undefined, then
i. Set method to ? GetMethod(V, @@dispose).
2. Else,
a. Let method be ? GetMethod(V, @@dispose).
3. Return method.
GetMethod ( V, P )
1. Let func be ? GetV(V, P).
2. If func is either undefined or null, return undefined.
3. ...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.throws(TypeError, function() {
stack.use({ [Symbol.dispose]: null });
}, 'true');

View File

@ -0,0 +1,58 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Throws if the argument has an undefined-valued Symbol.dispose property.
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
...
CreateDisposableResource ( V, hint [ , method ] )
1. If method is not present, then
a. If V is either null or undefined, then
i. Set V to undefined
ii. Set method to undefined
b. Else,
i. If Type(V) is not Object, throw a TypeError exception.
ii. Set method to ? GetDisposeMethod(V, hint).
iii. If method is undefined, throw a TypeError exception.
...
GetDisposeMethod ( V, hint )
1. If hint is async-dispose, then
a. Let method be ? GetMethod(V, @@asyncDispose).
b. If method is undefined, then
i. Set method to ? GetMethod(V, @@dispose).
2. Else,
a. Let method be ? GetMethod(V, @@dispose).
3. Return method.
GetMethod ( V, P )
1. Let func be ? GetV(V, P).
2. If func is either undefined or null, return undefined.
3. ...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.throws(TypeError, function() {
stack.use({ [Symbol.dispose]: undefined });
}, 'true');

View File

@ -0,0 +1,78 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Throws if the argument has a non-null, non-undefined, non-callable Symbol.dispose property.
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
...
CreateDisposableResource ( V, hint [ , method ] )
1. If method is not present, then
a. If V is either null or undefined, then
i. Set V to undefined
ii. Set method to undefined
b. Else,
i. If Type(V) is not Object, throw a TypeError exception.
ii. Set method to ? GetDisposeMethod(V, hint).
iii. If method is undefined, throw a TypeError exception.
2. Else,
a. ...
3. Return the DisposableResource Record { [[ResourceValue]]: V, [[Hint]]: hint, [[DisposeMethod]]: method }.
GetDisposeMethod ( V, hint )
1. If hint is async-dispose, then
a. Let method be ? GetMethod(V, @@asyncDispose).
b. If method is undefined, then
i. Set method to ? GetMethod(V, @@dispose).
2. Else,
a. Let method be ? GetMethod(V, @@dispose).
...
GetMethod ( V, P )
1. Let func be ? GetV(V, P).
2. If func is either undefined or null, return undefined.
3. If IsCallable(func) is false, throw a TypeError exception.
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.throws(TypeError, function() {
stack.use({ [Symbol.dispose]: true });
}, 'true');
assert.throws(TypeError, function() {
stack.use({ [Symbol.dispose]: false });
}, 'false');
assert.throws(TypeError, function() {
stack.use({ [Symbol.dispose]: 1 });
}, 'number');
assert.throws(TypeError, function() {
stack.use({ [Symbol.dispose]: 'object' });
}, 'string');
var s = Symbol();
assert.throws(TypeError, function() {
stack.use({ [Symbol.dispose]: s });
}, 'symbol');

View File

@ -0,0 +1,59 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-disposablestack.prototype.use
description: Throws if the argument is an object that does not have a Symbol.dispose property.
info: |
DisposableStack.prototype.use ( value )
1. Let disposableStack be the this value.
2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose).
...
AddDisposableResource ( disposeCapability, V, hint [, method ] )
1. If method is not present then,
a. If V is either null or undefined and hint is sync-dispose, then
i. Return unused
b. Let resource be ? CreateDisposableResource(V, hint).
...
CreateDisposableResource ( V, hint [ , method ] )
1. If method is not present, then
a. If V is either null or undefined, then
i. Set V to undefined
ii. Set method to undefined
b. Else,
i. If Type(V) is not Object, throw a TypeError exception.
ii. Set method to ? GetDisposeMethod(V, hint).
iii. If method is undefined, throw a TypeError exception.
...
GetDisposeMethod ( V, hint )
1. If hint is async-dispose, then
a. Let method be ? GetMethod(V, @@asyncDispose).
b. If method is undefined, then
i. Set method to ? GetMethod(V, @@dispose).
2. Else,
a. Let method be ? GetMethod(V, @@dispose).
3. Return method.
GetMethod ( V, P )
1. Let func be ? GetV(V, P).
2. If func is either undefined or null, return undefined.
3. If IsCallable(func) is false, throw a TypeError exception.
...
features: [explicit-resource-management]
---*/
var stack = new DisposableStack();
assert.throws(TypeError, function() {
stack.use({ });
}, 'true');