diff --git a/src/Algorithm.ts b/src/Algorithm.ts index 71580cbb..205edd9e 100644 --- a/src/Algorithm.ts +++ b/src/Algorithm.ts @@ -87,13 +87,12 @@ export default class Algorithm extends Builder { continue; } const completionyThing = part.contents.match( - /\b(ReturnIfAbrupt|throw|Return (Normal|Throw)?Completion|the result of evaluating)\b|(?<=[\s(])\?\s/i + /\b(ReturnIfAbrupt\b|(^|(?<=, ))[tT]hrow (a\b|the\b|$)|[rR]eturn (Normal|Throw|Return)?Completion\(|[rR]eturn( a| a new| the)? Completion Record\b|the result of evaluating\b)|(?<=[\s(])\?\s/ ); if (completionyThing != null) { if (returnType?.kind === 'completion') { containsAnyCompletionyThings = true; - } else if (clause.aoid !== 'GeneratorStart') { - // TODO: remove above exception when the spec is more coherent (https://github.com/tc39/ecma262/pull/2429) + } else { spec.warn({ type: 'contents', ruleId: 'completiony-thing-in-non-completion-algorithm', diff --git a/test/typecheck.js b/test/typecheck.js index c2d2a7fe..5833605e 100644 --- a/test/typecheck.js +++ b/test/typecheck.js @@ -254,7 +254,50 @@ describe('typechecking completions', () => {
- 1. ${M}Throw a new TypeError. + 1. ${M}Throw a *TypeError* exception. + + + `, + { + ruleId: 'completiony-thing-in-non-completion-algorithm', + nodeType: 'emu-alg', + message: + 'this would return a Completion Record, but the containing AO is declared not to return a Completion Record', + } + ); + + await assertLint( + positioned` + +

+ ExampleAlg (): a Number +

+
+
+ + 1. If some condition is met, ${M}throw a *TypeError* exception. + +
+ `, + { + ruleId: 'completiony-thing-in-non-completion-algorithm', + nodeType: 'emu-alg', + message: + 'this would return a Completion Record, but the containing AO is declared not to return a Completion Record', + } + ); + + await assertLint( + positioned` + +

+ ExampleAlg (): a Number +

+
+
+ + 1. Let _foo_ be a thing. + 1. ${M}Throw _foo_.
`, @@ -290,6 +333,28 @@ describe('typechecking completions', () => { extraBiblios: [biblio], } ); + + await assertLint( + positioned` + +

+ ExampleAlg (): a Number +

+
+
+ + 1. Let _x_ be 0. + 1. ${M}Return Completion Record { [[Type]]: ~return~, [[Value]]: _x_, [[Target]]: ~empty~ }. + +
+ `, + { + ruleId: 'completiony-thing-in-non-completion-algorithm', + nodeType: 'emu-alg', + message: + 'this would return a Completion Record, but the containing AO is declared not to return a Completion Record', + } + ); }); it('negative', async () => { @@ -314,6 +379,26 @@ describe('typechecking completions', () => { extraBiblios: [biblio], } ); + + await assertLintFree( + ` + +

+ ExampleAlg (): a Number +

+
+
+ + 1. Do something with Completion(0). + 1. NOTE: This will not throw a *TypeError* exception. + 1. Consider whether something is a return completion. + +
+ `, + { + extraBiblios: [biblio], + } + ); }); }); @@ -507,7 +592,7 @@ describe('typechecking completions', () => {
- 1. Throw something. + 1. Throw a *TypeError* exception.