Break out of speculative parsing on bad parameter initializer (#19158)
* Break out of speculative parsing on bad parameter initializer * Remove uses of 'finally' * give up -> stop * Do without exceptions * Remove `resetAfterSpeculation` * Use Fail and FailList objects * Remove `inSpeculation` parameter to parseDelimitedList * Don't use `createNodeArray`, it's not always in scope * Move Fail and FailList inside initializeState * More code review * More code review
This commit is contained in:
parent
120fb6fc95
commit
e7df83263d
|
@ -531,6 +531,18 @@ namespace ts {
|
|||
let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
interface Fail extends Node { kind: SyntaxKind.Unknown; }
|
||||
interface FailList extends NodeArray<Node> { pos: -1; }
|
||||
let Fail: Fail;
|
||||
let FailList: FailList;
|
||||
function isFail(x: Node | undefined): x is Fail {
|
||||
Debug.assert(Fail !== undefined);
|
||||
return x === Fail;
|
||||
}
|
||||
function isFailList(x: NodeArray<Node> | undefined): x is FailList {
|
||||
Debug.assert(Fail !== undefined);
|
||||
return x === FailList;
|
||||
}
|
||||
// tslint:enable variable-name
|
||||
|
||||
let sourceFile: SourceFile;
|
||||
|
@ -681,6 +693,9 @@ namespace ts {
|
|||
IdentifierConstructor = objectAllocator.getIdentifierConstructor();
|
||||
SourceFileConstructor = objectAllocator.getSourceFileConstructor();
|
||||
|
||||
Fail = createNode(SyntaxKind.Unknown) as Fail;
|
||||
FailList = createNodeArray([], -1) as FailList;
|
||||
|
||||
sourceText = _sourceText;
|
||||
syntaxCursor = _syntaxCursor;
|
||||
|
||||
|
@ -736,7 +751,7 @@ namespace ts {
|
|||
processReferenceComments(sourceFile);
|
||||
|
||||
sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement);
|
||||
Debug.assert(token() === SyntaxKind.EndOfFileToken);
|
||||
Debug.assertEqual(token(), SyntaxKind.EndOfFileToken);
|
||||
sourceFile.endOfFileToken = addJSDocComment(parseTokenNode() as EndOfFileToken);
|
||||
|
||||
setExternalModuleIndicator(sourceFile);
|
||||
|
@ -1003,7 +1018,7 @@ namespace ts {
|
|||
return currentToken = scanner.scanJsxAttributeValue();
|
||||
}
|
||||
|
||||
function speculationHelper<T>(callback: () => T, isLookAhead: boolean): T {
|
||||
function speculationHelper<T>(callback: () => T, isLookAhead: boolean): T | undefined {
|
||||
// Keep track of the state we'll need to rollback to if lookahead fails (or if the
|
||||
// caller asked us to always reset our state).
|
||||
const saveToken = currentToken;
|
||||
|
@ -1015,6 +1030,7 @@ namespace ts {
|
|||
// descent nature of our parser. However, we still store this here just so we can
|
||||
// assert that invariant holds.
|
||||
const saveContextFlags = contextFlags;
|
||||
const saveParsingContext = parsingContext;
|
||||
|
||||
// If we're only looking ahead, then tell the scanner to only lookahead as well.
|
||||
// Otherwise, if we're actually speculatively parsing, then tell the scanner to do the
|
||||
|
@ -1023,7 +1039,8 @@ namespace ts {
|
|||
? scanner.lookAhead(callback)
|
||||
: scanner.tryScan(callback);
|
||||
|
||||
Debug.assert(saveContextFlags === contextFlags);
|
||||
Debug.assertEqual(saveContextFlags, contextFlags);
|
||||
Debug.assertEqual(saveParsingContext, parsingContext);
|
||||
|
||||
// If our callback returned something 'falsy' or we're just looking ahead,
|
||||
// then unconditionally restore us to where we were.
|
||||
|
@ -1577,7 +1594,7 @@ namespace ts {
|
|||
return createNodeArray(list, listPos);
|
||||
}
|
||||
|
||||
function parseListElement<T extends Node>(parsingContext: ParsingContext, parseElement: () => T): T {
|
||||
function parseListElement<T extends Node | Fail>(parsingContext: ParsingContext, parseElement: () => T): T {
|
||||
const node = currentNode(parsingContext);
|
||||
if (node) {
|
||||
return <T>consumeNode(node);
|
||||
|
@ -1901,17 +1918,24 @@ namespace ts {
|
|||
}
|
||||
|
||||
// Parses a comma-delimited list of elements
|
||||
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T> {
|
||||
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T>;
|
||||
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T | Fail, considerSemicolonAsDelimiter?: boolean): NodeArray<T> | FailList;
|
||||
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T | Fail, considerSemicolonAsDelimiter?: boolean): NodeArray<T> | FailList {
|
||||
const saveParsingContext = parsingContext;
|
||||
parsingContext |= 1 << kind;
|
||||
const list = [];
|
||||
const list: T[] = [];
|
||||
const listPos = getNodePos();
|
||||
|
||||
let commaStart = -1; // Meaning the previous token was not a comma
|
||||
while (true) {
|
||||
if (isListElement(kind, /*inErrorRecovery*/ false)) {
|
||||
const startPos = scanner.getStartPos();
|
||||
list.push(parseListElement(kind, parseElement));
|
||||
const elem = parseListElement(kind, parseElement);
|
||||
if (isFail(elem)) {
|
||||
parsingContext = saveParsingContext;
|
||||
return FailList;
|
||||
}
|
||||
list.push(elem);
|
||||
commaStart = scanner.getTokenPos();
|
||||
|
||||
if (parseOptional(SyntaxKind.CommaToken)) {
|
||||
|
@ -2271,7 +2295,13 @@ namespace ts {
|
|||
isStartOfType(/*inStartOfParameter*/ true);
|
||||
}
|
||||
|
||||
function parseParameter(requireEqualsToken?: boolean): ParameterDeclaration {
|
||||
function tryParseParameter(): ParameterDeclaration | Fail {
|
||||
return parseParameterWorker(/*inSpeculation*/ true);
|
||||
}
|
||||
function parseParameter(): ParameterDeclaration {
|
||||
return parseParameterWorker(/*inSpeculation*/ false) as ParameterDeclaration;
|
||||
}
|
||||
function parseParameterWorker(inSpeculation: boolean): ParameterDeclaration | Fail {
|
||||
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter);
|
||||
if (token() === SyntaxKind.ThisKeyword) {
|
||||
node.name = createIdentifier(/*isIdentifier*/ true);
|
||||
|
@ -2285,7 +2315,11 @@ namespace ts {
|
|||
|
||||
// FormalParameter [Yield,Await]:
|
||||
// BindingElement[?Yield,?Await]
|
||||
node.name = parseIdentifierOrPattern();
|
||||
const name = parseIdentifierOrPattern(inSpeculation);
|
||||
if (isFail(name)) {
|
||||
return Fail;
|
||||
}
|
||||
node.name = name;
|
||||
if (getFullWidth(node.name) === 0 && !hasModifiers(node) && isModifierKind(token())) {
|
||||
// in cases like
|
||||
// 'use strict'
|
||||
|
@ -2300,20 +2334,27 @@ namespace ts {
|
|||
|
||||
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
|
||||
node.type = parseParameterType();
|
||||
node.initializer = parseInitializer(/*inParameter*/ true, requireEqualsToken);
|
||||
const initializer = parseInitializer(/*inParameter*/ true, inSpeculation);
|
||||
if (isFail(initializer)) {
|
||||
return Fail;
|
||||
}
|
||||
node.initializer = initializer;
|
||||
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
|
||||
function fillSignature(
|
||||
returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
|
||||
flags: SignatureFlags,
|
||||
signature: SignatureDeclaration): void {
|
||||
/** @return 'true' on success. */
|
||||
function fillSignature(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, flags: SignatureFlags, signature: SignatureDeclaration, inSpeculation?: boolean): boolean {
|
||||
if (!(flags & SignatureFlags.JSDoc)) {
|
||||
signature.typeParameters = parseTypeParameters();
|
||||
}
|
||||
signature.parameters = parseParameterList(flags);
|
||||
const parameters = parseParameterList(flags, inSpeculation);
|
||||
if (isFailList(parameters)) {
|
||||
return false;
|
||||
}
|
||||
signature.parameters = parameters;
|
||||
signature.type = parseReturnType(returnToken, !!(flags & SignatureFlags.Type));
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined {
|
||||
|
@ -2336,7 +2377,7 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
function parseParameterList(flags: SignatureFlags) {
|
||||
function parseParameterList(flags: SignatureFlags, inSpeculation: boolean): NodeArray<ParameterDeclaration> | FailList {
|
||||
// FormalParameters [Yield,Await]: (modified)
|
||||
// [empty]
|
||||
// FormalParameterList[?Yield,Await]
|
||||
|
@ -2357,9 +2398,9 @@ namespace ts {
|
|||
setYieldContext(!!(flags & SignatureFlags.Yield));
|
||||
setAwaitContext(!!(flags & SignatureFlags.Await));
|
||||
|
||||
const result = parseDelimitedList(ParsingContext.Parameters,
|
||||
flags & SignatureFlags.JSDoc ? parseJSDocParameter : () => parseParameter(!!(flags & SignatureFlags.RequireCompleteParameterList)));
|
||||
|
||||
const result = parseDelimitedList<ParameterDeclaration>(
|
||||
ParsingContext.Parameters,
|
||||
flags & SignatureFlags.JSDoc ? parseJSDocParameter : inSpeculation ? tryParseParameter : parseParameter);
|
||||
setYieldContext(savedYieldContext);
|
||||
setAwaitContext(savedAwaitContext);
|
||||
|
||||
|
@ -3032,14 +3073,16 @@ namespace ts {
|
|||
while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) {
|
||||
expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher());
|
||||
}
|
||||
|
||||
if (saveDecoratorContext) {
|
||||
setDecoratorContext(/*val*/ true);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
function parseInitializer(inParameter: boolean, requireEqualsToken?: boolean): Expression {
|
||||
function parseInitializer(inParameter: boolean): Expression | undefined;
|
||||
function parseInitializer(inParameter: boolean, inSpeculation?: boolean): Expression | Fail | undefined;
|
||||
function parseInitializer(inParameter: boolean, inSpeculation?: boolean): Expression | Fail | undefined {
|
||||
if (token() !== SyntaxKind.EqualsToken) {
|
||||
// It's not uncommon during typing for the user to miss writing the '=' token. Check if
|
||||
// there is no newline after the last token and if we're on an expression. If so, parse
|
||||
|
@ -3054,12 +3097,8 @@ namespace ts {
|
|||
// do not try to parse initializer
|
||||
return undefined;
|
||||
}
|
||||
if (inParameter && requireEqualsToken) {
|
||||
// = is required when speculatively parsing arrow function parameters,
|
||||
// so return a fake initializer as a signal that the equals token was missing
|
||||
const result = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics._0_expected, "=") as Identifier;
|
||||
result.escapedText = "= not found" as __String;
|
||||
return result;
|
||||
if (inSpeculation) {
|
||||
return Fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3225,7 +3264,7 @@ namespace ts {
|
|||
// it out, but don't allow any ambiguity, and return 'undefined' if this could be an
|
||||
// expression instead.
|
||||
const arrowFunction = triState === Tristate.True
|
||||
? parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ true)
|
||||
? parseParenthesizedArrowFunctionExpressionHead(/*inSpeculation*/ false)
|
||||
: tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead);
|
||||
|
||||
if (!arrowFunction) {
|
||||
|
@ -3373,7 +3412,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction {
|
||||
return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
|
||||
return parseParenthesizedArrowFunctionExpressionHead(/*inSpeculation*/ true);
|
||||
}
|
||||
|
||||
function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction | undefined {
|
||||
|
@ -3409,7 +3448,7 @@ namespace ts {
|
|||
return Tristate.False;
|
||||
}
|
||||
|
||||
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
|
||||
function parseParenthesizedArrowFunctionExpressionHead(inSpeculation: boolean): ArrowFunction | undefined {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
|
||||
node.modifiers = parseModifiersForArrowFunction();
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
|
@ -3420,7 +3459,10 @@ namespace ts {
|
|||
// a => (b => c)
|
||||
// And think that "(b =>" was actually a parenthesized arrow function with a missing
|
||||
// close paren.
|
||||
fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? SignatureFlags.None : SignatureFlags.RequireCompleteParameterList), node);
|
||||
|
||||
if (!fillSignature(SyntaxKind.ColonToken, isAsync | (inSpeculation ? SignatureFlags.RequireCompleteParameterList : SignatureFlags.None), node, inSpeculation)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If we couldn't get parameters, we definitely could not parse out an arrow function.
|
||||
if (!node.parameters) {
|
||||
|
@ -3435,8 +3477,7 @@ namespace ts {
|
|||
// - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
|
||||
//
|
||||
// So we need just a bit of lookahead to ensure that it can only be a signature.
|
||||
if (!allowAmbiguity && ((token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) ||
|
||||
find(node.parameters, p => p.initializer && ts.isIdentifier(p.initializer) && p.initializer.escapedText === "= not found"))) {
|
||||
if (inSpeculation && token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) {
|
||||
// Returning undefined here will cause our caller to rewind to where we started from.
|
||||
return undefined;
|
||||
}
|
||||
|
@ -4574,7 +4615,6 @@ namespace ts {
|
|||
if (saveDecoratorContext) {
|
||||
setDecoratorContext(/*val*/ false);
|
||||
}
|
||||
|
||||
const node = <FunctionExpression>createNode(SyntaxKind.FunctionExpression);
|
||||
node.modifiers = parseModifiers();
|
||||
parseExpected(SyntaxKind.FunctionKeyword);
|
||||
|
@ -4590,7 +4630,6 @@ namespace ts {
|
|||
|
||||
fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node);
|
||||
node.body = parseFunctionBlock(isGenerator | isAsync);
|
||||
|
||||
if (saveDecoratorContext) {
|
||||
setDecoratorContext(/*val*/ true);
|
||||
}
|
||||
|
@ -4653,7 +4692,6 @@ namespace ts {
|
|||
}
|
||||
|
||||
const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage);
|
||||
|
||||
if (saveDecoratorContext) {
|
||||
setDecoratorContext(/*val*/ true);
|
||||
}
|
||||
|
@ -5227,18 +5265,38 @@ namespace ts {
|
|||
|
||||
// DECLARATIONS
|
||||
|
||||
function tryParseArrayBindingElement(): ArrayBindingElement | Fail {
|
||||
return parseArrayBindingElementWorker(/*inSpeculation*/ true);
|
||||
}
|
||||
function parseArrayBindingElement(): ArrayBindingElement {
|
||||
return parseArrayBindingElementWorker(/*inSpeculation*/ false) as ArrayBindingElement;
|
||||
}
|
||||
function parseArrayBindingElementWorker(inSpeculation: boolean): ArrayBindingElement | Fail {
|
||||
if (token() === SyntaxKind.CommaToken) {
|
||||
return <OmittedExpression>createNode(SyntaxKind.OmittedExpression);
|
||||
}
|
||||
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
|
||||
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
node.name = parseIdentifierOrPattern();
|
||||
node.initializer = parseInitializer(/*inParameter*/ false);
|
||||
const name = parseIdentifierOrPattern(inSpeculation);
|
||||
if (isFail(name)) {
|
||||
return Fail;
|
||||
}
|
||||
node.name = name;
|
||||
const init = parseInitializer(/*inParameter*/ false, inSpeculation);
|
||||
if (isFail(init)) {
|
||||
return Fail;
|
||||
}
|
||||
node.initializer = init;
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function tryParseObjectBindingElement(): BindingElement | Fail {
|
||||
return parseObjectBindingElementWorker(/*inSpeculation*/ true);
|
||||
}
|
||||
function parseObjectBindingElement(): BindingElement {
|
||||
return parseObjectBindingElementWorker(/*inSpeculation*/ false) as BindingElement;
|
||||
}
|
||||
function parseObjectBindingElementWorker(inSpeculation: boolean): BindingElement | Fail {
|
||||
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
|
||||
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
const tokenIsIdentifier = isIdentifier();
|
||||
|
@ -5249,24 +5307,46 @@ namespace ts {
|
|||
else {
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.propertyName = propertyName;
|
||||
node.name = parseIdentifierOrPattern();
|
||||
const name = parseIdentifierOrPattern(inSpeculation);
|
||||
if (isFail(name)) {
|
||||
return Fail;
|
||||
}
|
||||
node.name = name;
|
||||
}
|
||||
node.initializer = parseInitializer(/*inParameter*/ false);
|
||||
const init = parseInitializer(/*inParameter*/ false, inSpeculation);
|
||||
if (isFail(init)) {
|
||||
return Fail;
|
||||
}
|
||||
node.initializer = init;
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseObjectBindingPattern(): ObjectBindingPattern {
|
||||
function parseObjectBindingPattern(inSpeculation: boolean): ObjectBindingPattern | Fail {
|
||||
const node = <ObjectBindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
|
||||
parseExpected(SyntaxKind.OpenBraceToken);
|
||||
node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement);
|
||||
const elements = parseDelimitedList<BindingElement>(
|
||||
ParsingContext.ObjectBindingElements,
|
||||
inSpeculation ? tryParseObjectBindingElement : parseObjectBindingElement,
|
||||
/*considerSemicolonAsDelimiter*/ undefined);
|
||||
if (isFailList(elements)) {
|
||||
return Fail;
|
||||
}
|
||||
node.elements = elements;
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseArrayBindingPattern(): ArrayBindingPattern {
|
||||
function parseArrayBindingPattern(inSpeculation: boolean): ArrayBindingPattern | Fail {
|
||||
const node = <ArrayBindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement);
|
||||
const elements = parseDelimitedList<BindingElement | OmittedExpression>(
|
||||
ParsingContext.ArrayBindingElements,
|
||||
inSpeculation ? tryParseArrayBindingElement : parseArrayBindingElement,
|
||||
/*considerSemicolonAsDelimiter*/ undefined);
|
||||
if (isFailList(elements)) {
|
||||
return Fail;
|
||||
}
|
||||
node.elements = elements;
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
@ -5275,12 +5355,14 @@ namespace ts {
|
|||
return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken || isIdentifier();
|
||||
}
|
||||
|
||||
function parseIdentifierOrPattern(): Identifier | BindingPattern {
|
||||
function parseIdentifierOrPattern(): Identifier | BindingPattern;
|
||||
function parseIdentifierOrPattern(inSpeculation: boolean): Identifier | BindingPattern | Fail;
|
||||
function parseIdentifierOrPattern(inSpeculation?: boolean): Identifier | BindingPattern | Fail {
|
||||
if (token() === SyntaxKind.OpenBracketToken) {
|
||||
return parseArrayBindingPattern();
|
||||
return parseArrayBindingPattern(inSpeculation);
|
||||
}
|
||||
if (token() === SyntaxKind.OpenBraceToken) {
|
||||
return parseObjectBindingPattern();
|
||||
return parseObjectBindingPattern(inSpeculation);
|
||||
}
|
||||
return parseIdentifier();
|
||||
}
|
||||
|
@ -5328,9 +5410,7 @@ namespace ts {
|
|||
else {
|
||||
const savedDisallowIn = inDisallowInContext();
|
||||
setDisallowInContext(inForStatementInitializer);
|
||||
|
||||
node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, parseVariableDeclaration);
|
||||
|
||||
setDisallowInContext(savedDisallowIn);
|
||||
}
|
||||
|
||||
|
@ -5428,7 +5508,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function parseNonParameterInitializer() {
|
||||
function parseNonParameterInitializer(): Expression | undefined {
|
||||
return parseInitializer(/*inParameter*/ false);
|
||||
}
|
||||
|
||||
|
|
16
tests/baselines/reference/parserArrowFunctionExpression7.js
Normal file
16
tests/baselines/reference/parserArrowFunctionExpression7.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
//// [parserArrowFunctionExpression7.ts]
|
||||
({
|
||||
async m() {
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//// [parserArrowFunctionExpression7.js]
|
||||
({
|
||||
async m() {
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression7.ts ===
|
||||
({
|
||||
async m() {
|
||||
>m : Symbol(m, Decl(parserArrowFunctionExpression7.ts, 0, 2))
|
||||
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
=== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression7.ts ===
|
||||
({
|
||||
>({ async m() { for (;;) { } }}) : { m(): Promise<void>; }
|
||||
>{ async m() { for (;;) { } }} : { m(): Promise<void>; }
|
||||
|
||||
async m() {
|
||||
>m : () => Promise<void>
|
||||
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// @target: esnext
|
||||
({
|
||||
async m() {
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue