From b44f6e47d653419b1f47baf6734bd0942a3f15d0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 12 Dec 2015 15:56:43 -0800 Subject: [PATCH 1/2] Simplify deferred checking of function, class, and accessor bodies. --- src/compiler/checker.ts | 155 +++++++++++----------------------------- 1 file changed, 40 insertions(+), 115 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ea23255472d2a..e4cf101946a49 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -161,6 +161,8 @@ namespace ts { let jsxElementClassType: Type; + let deferredNodes: Node[]; + const tupleTypes: Map = {}; const unionTypes: Map = {}; const intersectionTypes: Map = {}; @@ -10123,6 +10125,7 @@ namespace ts { if (!contextChecked) { checkSignatureDeclaration(node); + checkNodeDeferred(node); } } } @@ -10135,7 +10138,7 @@ namespace ts { return type; } - function checkFunctionExpressionOrObjectLiteralMethodBody(node: ArrowFunction | FunctionExpression | MethodDeclaration) { + function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const isAsync = isAsyncFunctionLike(node); @@ -10178,8 +10181,6 @@ namespace ts { checkTypeAssignableTo(exprType, returnOrPromisedType, node.body); } } - - checkFunctionAndClassExpressionBodies(node.body); } } } @@ -11428,13 +11429,13 @@ namespace ts { if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { checkSourceElement(node.body); } + else { + checkNodeDeferred(node); + } } - function checkObjectLiteralAccessorBody(node: AccessorDeclaration) { - if (node.body) { - checkSourceElement(node.body); - checkFunctionAndClassExpressionBodies(node.body); - } + function checkAccessorDeferred(node: AccessorDeclaration) { + checkSourceElement(node.body); } function checkMissingDeclaration(node: Node) { @@ -12373,11 +12374,7 @@ namespace ts { if (node.kind === SyntaxKind.Block) { checkGrammarStatementInAmbientContext(node); } - forEach(node.statements, checkSourceElement); - if (isFunctionBlock(node) || node.kind === SyntaxKind.ModuleBlock) { - checkFunctionAndClassExpressionBodies(node); - } } function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { @@ -13406,15 +13403,19 @@ namespace ts { function checkClassExpression(node: ClassExpression): Type { checkClassLikeDeclaration(node); + checkNodeDeferred(node); return getTypeOfSymbol(getSymbolOfNode(node)); } + function checkClassExpressionDeferred(node: ClassExpression) { + forEach(node.members, checkSourceElement); + } + function checkClassDeclaration(node: ClassDeclaration) { if (!node.name && !(node.flags & NodeFlags.Default)) { grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); } checkClassLikeDeclaration(node); - forEach(node.members, checkSourceElement); } @@ -14478,107 +14479,29 @@ namespace ts { // Here, performing a full type check of the body of the function expression whilst in the process of // determining the type of foo would cause foo to be given type any because of the recursive reference. // Delaying the type check of the body ensures foo has been assigned a type. - function checkFunctionAndClassExpressionBodies(node: Node): void { - switch (node.kind) { - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - forEach((node).parameters, checkFunctionAndClassExpressionBodies); - checkFunctionExpressionOrObjectLiteralMethodBody(node); - break; - case SyntaxKind.ClassExpression: - forEach((node).members, checkSourceElement); - forEachChild(node, checkFunctionAndClassExpressionBodies); - break; - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - forEach(node.decorators, checkFunctionAndClassExpressionBodies); - forEach((node).parameters, checkFunctionAndClassExpressionBodies); - if (isObjectLiteralMethod(node)) { - checkFunctionExpressionOrObjectLiteralMethodBody(node); - } - break; - case SyntaxKind.Constructor: - case SyntaxKind.FunctionDeclaration: - forEach((node).parameters, checkFunctionAndClassExpressionBodies); - break; - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - forEach((node).parameters, checkFunctionAndClassExpressionBodies); - if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { - checkObjectLiteralAccessorBody(node); - } - break; - case SyntaxKind.WithStatement: - checkFunctionAndClassExpressionBodies((node).expression); - break; - case SyntaxKind.Decorator: - case SyntaxKind.Parameter: - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - case SyntaxKind.BindingElement: - case SyntaxKind.ArrayLiteralExpression: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.PropertyAccessExpression: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - case SyntaxKind.TaggedTemplateExpression: - case SyntaxKind.TemplateExpression: - case SyntaxKind.TemplateSpan: - case SyntaxKind.TypeAssertionExpression: - case SyntaxKind.AsExpression: - case SyntaxKind.ParenthesizedExpression: - case SyntaxKind.TypeOfExpression: - case SyntaxKind.VoidExpression: - case SyntaxKind.AwaitExpression: - case SyntaxKind.DeleteExpression: - case SyntaxKind.PrefixUnaryExpression: - case SyntaxKind.PostfixUnaryExpression: - case SyntaxKind.BinaryExpression: - case SyntaxKind.ConditionalExpression: - case SyntaxKind.SpreadElementExpression: - case SyntaxKind.YieldExpression: - case SyntaxKind.Block: - case SyntaxKind.ModuleBlock: - case SyntaxKind.VariableStatement: - case SyntaxKind.ExpressionStatement: - case SyntaxKind.IfStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - case SyntaxKind.ContinueStatement: - case SyntaxKind.BreakStatement: - case SyntaxKind.ReturnStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.CaseBlock: - case SyntaxKind.CaseClause: - case SyntaxKind.DefaultClause: - case SyntaxKind.LabeledStatement: - case SyntaxKind.ThrowStatement: - case SyntaxKind.TryStatement: - case SyntaxKind.CatchClause: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.VariableDeclarationList: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.HeritageClause: - case SyntaxKind.ExpressionWithTypeArguments: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.EnumMember: - case SyntaxKind.ExportAssignment: - case SyntaxKind.SourceFile: - case SyntaxKind.JsxExpression: - case SyntaxKind.JsxElement: - case SyntaxKind.JsxSelfClosingElement: - case SyntaxKind.JsxAttribute: - case SyntaxKind.JsxSpreadAttribute: - case SyntaxKind.JsxOpeningElement: - forEachChild(node, checkFunctionAndClassExpressionBodies); - break; + function checkNodeDeferred(node: Node) { + if (deferredNodes) { + deferredNodes.push(node); + } + } + + function checkDeferredNodes() { + for (const node of deferredNodes) { + switch (node.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + checkFunctionExpressionOrObjectLiteralMethodDeferred(node); + break; + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + checkAccessorDeferred(node); + break; + case SyntaxKind.ClassExpression: + checkClassExpressionDeferred(node); + break; + } } } @@ -14613,8 +14536,10 @@ namespace ts { emitAwaiter = false; potentialThisCollisions.length = 0; + deferredNodes = []; forEach(node.statements, checkSourceElement); - checkFunctionAndClassExpressionBodies(node); + checkDeferredNodes(); + deferredNodes = undefined; if (isExternalOrCommonJsModule(node)) { checkExternalModuleExports(node); From 91b93439f12a911bc83fbc3399a9a739a619721a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 12 Dec 2015 15:57:39 -0800 Subject: [PATCH 2/2] Accepting new baselines --- ...nePropertyAccessAndArrowFunctionIndent1.errors.txt | 11 +---------- .../multiLinePropertyAccessAndArrowFunctionIndent1.js | 3 +-- ...atementIsNotAMemberVariableDeclaration1.errors.txt | 5 +---- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt b/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt index abf11dc9dbaab..48a1da7d22ccf 100644 --- a/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt +++ b/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.errors.txt @@ -1,20 +1,11 @@ tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(1,1): error TS1108: A 'return' statement can only be used within a function body. -tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(1,18): error TS2304: Cannot find name 'role'. -tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(2,18): error TS2304: Cannot find name 'Role'. -tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts(4,26): error TS2503: Cannot find namespace 'ng'. -==== tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts (4 errors) ==== +==== tests/cases/compiler/multiLinePropertyAccessAndArrowFunctionIndent1.ts (1 errors) ==== return this.edit(role) ~~~~~~ !!! error TS1108: A 'return' statement can only be used within a function body. - ~~~~ -!!! error TS2304: Cannot find name 'role'. .then((role: Role) => - ~~~~ -!!! error TS2304: Cannot find name 'Role'. this.roleService.add(role) .then((data: ng.IHttpPromiseCallbackArg) => data.data)); - ~~ -!!! error TS2503: Cannot find namespace 'ng'. \ No newline at end of file diff --git a/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.js b/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.js index 2ada9f1bb5217..4821f1fe69c68 100644 --- a/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.js +++ b/tests/baselines/reference/multiLinePropertyAccessAndArrowFunctionIndent1.js @@ -6,9 +6,8 @@ return this.edit(role) //// [multiLinePropertyAccessAndArrowFunctionIndent1.js] -var _this = this; return this.edit(role) .then(function (role) { - return _this.roleService.add(role) + return this.roleService.add(role) .then(function (data) { return data.data; }); }); diff --git a/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt b/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt index 72cfee58e5434..0532fd28d636b 100644 --- a/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt +++ b/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt @@ -1,8 +1,7 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMemberVariableDeclaration1.ts(1,1): error TS1108: A 'return' statement can only be used within a function body. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMemberVariableDeclaration1.ts(6,5): error TS2304: Cannot find name 'private'. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMemberVariableDeclaration1.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMemberVariableDeclaration1.ts (1 errors) ==== return { ~~~~~~ !!! error TS1108: A 'return' statement can only be used within a function body. @@ -11,8 +10,6 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMe // 'private' should not be considered a member variable here. private[key] = value; - ~~~~~~~ -!!! error TS2304: Cannot find name 'private'. }