Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support using and await using declarations #54505

Merged
merged 33 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0cb73b3
Add support for 'using' and 'await using' declarations
rbuckton May 24, 2023
0647856
Move NamedEvaluation to its own file
rbuckton May 26, 2023
8f082fc
Remove unnecessary copyStandardPrologue call
rbuckton May 26, 2023
688771f
Reorder transforms
rbuckton May 30, 2023
80d0a84
Merge branch 'main' into using-declaration
rbuckton Jun 1, 2023
a17aead
Used named evaluation transform in class fields, emit cleanup
rbuckton Jun 1, 2023
25a2fd3
Add --coverage for tests, remove unused NamedEvaluation code
rbuckton Jun 2, 2023
40f546b
Remove temporary debug/diagnostic code
rbuckton Jun 2, 2023
e0b9c73
Revert '--coverage' in favor of #54499
rbuckton Jun 2, 2023
08f41bd
Remove unused sameMapDefined function from core
rbuckton Jun 2, 2023
7360338
Revert inconsequential change in import list in debug.ts
rbuckton Jun 2, 2023
587a1a4
Revert changes to track factory source in favor of #51307
rbuckton Jun 2, 2023
3be9cf0
Clean up function names in transformers/module/module.ts
rbuckton Jun 2, 2023
0b77050
Minor jsdoc comment cleanup
rbuckton Jun 2, 2023
bba71b1
Add additional documentation comments to the 'esnext' transform
rbuckton Jun 2, 2023
2d4e506
Further cleanup of NamedEvaluation
rbuckton Jun 5, 2023
ae6cbaf
PR Feedback
rbuckton Jun 6, 2023
afa64ca
Add test verifying we now check excess decls in a for-in/of
rbuckton Jun 6, 2023
5b6adea
Add declaration emit tests
rbuckton Jun 8, 2023
7964b5f
Merge branch 'main' into using-declaration
rbuckton Jun 8, 2023
0435db0
Reduce calls to getCombinedNodeFlags
rbuckton Jun 8, 2023
246a9a3
Only cache the last combined node flags
rbuckton Jun 9, 2023
21b3e03
Cache getCombinedNodeFlags result in checker
rbuckton Jun 9, 2023
4a5ca67
Cache getCombinedModifierFlags result in checker
rbuckton Jun 9, 2023
b763f82
Add local, caching version of isVarConst to checker
rbuckton Jun 9, 2023
08a1434
Merge branch 'main' into using-declaration
rbuckton Jun 9, 2023
2fc9bcf
Merge branch 'main' into using-declaration
rbuckton Jun 12, 2023
1e8f045
Merge branch 'main' into using-declaration
rbuckton Jun 13, 2023
3dc4011
Add tests and report better errors for 'await using'
rbuckton Jun 15, 2023
8ad153a
PR feedback
rbuckton Jun 21, 2023
51870e1
Add fallback in helpers when SuppressedError does not exist
rbuckton Jun 21, 2023
df5e591
Use more iterations in evaluation tests
rbuckton Jun 21, 2023
558a502
Treat underscore-prefixed identifiers as used locals for 'using'/'awa…
rbuckton Jun 21, 2023
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
Prev Previous commit
Next Next commit
Add fallback in helpers when SuppressedError does not exist
  • Loading branch information
rbuckton committed Jun 21, 2023
commit 51870e184bb61bdf2d8e6c22a5a0ea7cad89a562
41 changes: 23 additions & 18 deletions src/compiler/factory/emitHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1425,26 +1425,31 @@ export const disposeResourcesHelper: UnscopedEmitHelper = {
importName: "__disposeResources",
scoped: false,
text: `
var __disposeResources = (this && this.__disposeResources) || function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error) : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
if (env.hasError) throw env.error;
}
return next();
};`
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});`
};

let allUnscopedEmitHelpers: ReadonlyMap<string, UnscopedEmitHelper> | undefined;
Expand Down
47 changes: 47 additions & 0 deletions src/testRunner/unittests/evaluation/awaitUsingDeclarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,53 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => {
]);
});

it("'await using' in Block, 'throw' in body and dispose, no global SuppressedError (es2018)", async () => {
const { main, output } = evaluator.evaluateTypeScript(`
export const output: any[] = [];

const disposable = {
async [Symbol.asyncDispose]() {
output.push("disposed");
throw "dispose error";
}
};

function body() {
output.push("body");
throw "body error";
}

export async function main() {
output.push("before try");
try {
output.push("enter try");
await using _ = disposable;
body();
output.push("exit try");
}
catch (e) {
output.push(e);
}
output.push("after try");
}
`, { target: ts.ScriptTarget.ES2018 });

await main();

assert.deepEqual(output.slice(0, 4), [
"before try",
"enter try",
"body",
"disposed"]);
assert.instanceOf(output[4], Error);
assert.strictEqual(output[4].name, "SuppressedError");
assert.strictEqual(output[4].error, "dispose error");
assert.strictEqual(output[4].suppressed, "body error");
assert.deepEqual(output.slice(5), [
"after try"
]);
});

it("'await using' in Block, 'return' in body (es2018)", async () => {
const { main, output } = evaluator.evaluateTypeScript(`
export const output: any[] = [];
Expand Down
47 changes: 47 additions & 0 deletions src/testRunner/unittests/evaluation/usingDeclarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,53 @@ describe("unittests:: evaluation:: usingDeclarations", () => {
]);
});

it("'using' in Block, 'throw' in body and dispose, no global SuppressedError (es2018)", () => {
const { main, output } = evaluator.evaluateTypeScript(`
export const output: any[] = [];

const disposable = {
[Symbol.dispose]() {
output.push("disposed");
throw "dispose error";
}
};

function body() {
output.push("body");
throw "body error";
}

export function main() {
output.push("before try");
try {
output.push("enter try");
using _ = disposable;
body();
output.push("exit try");
}
catch (e) {
output.push(e);
}
output.push("after try");
}
`, { target: ts.ScriptTarget.ES2018 });

main();

assert.deepEqual(output.slice(0, 4), [
"before try",
"enter try",
"body",
"disposed"]);
assert.instanceOf(output[4], Error);
assert.strictEqual(output[4].name, "SuppressedError");
assert.strictEqual(output[4].error, "dispose error");
assert.strictEqual(output[4].suppressed, "body error");
assert.deepEqual(output.slice(5), [
"after try"
]);
});

it("'using' in Block, 'return' in body (es2018)", () => {
const { main, output } = evaluator.evaluateTypeScript(`
export const output: any[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,26 +129,31 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error) : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
if (env.hasError) throw env.error;
}
return next();
};
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,26 +120,31 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error) : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
if (env.hasError) throw env.error;
}
return next();
};
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,26 +120,31 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error) : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
if (env.hasError) throw env.error;
}
return next();
};
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
async function af() {
const env_15 = { stack: [], error: void 0, hasError: false };
try {
Expand Down
43 changes: 24 additions & 19 deletions tests/baselines/reference/awaitUsingDeclarations.1(target=es5).js
Original file line number Diff line number Diff line change
Expand Up @@ -156,26 +156,31 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error) : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
}
if (env.hasError) throw env.error;
}
return next();
};
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
Expand Down
Loading