Skip to content

Commit c792fd2

Browse files
committed
Merge branch 'master' into fixAsyncReferecedImport
2 parents c108042 + b40079e commit c792fd2

18 files changed

+801
-327
lines changed

src/compiler/checker.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9871,31 +9871,39 @@ namespace ts {
98719871
}
98729872

98739873
// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
9874-
if (returnType && (returnType === voidType || isTypeAny(returnType))) {
9875-
return;
9876-
}
9877-
9878-
// if return type is not specified then we'll do the check only if 'noImplicitReturns' option is set
9879-
if (!returnType && !compilerOptions.noImplicitReturns) {
9874+
if (returnType === voidType || isTypeAny(returnType)) {
98809875
return;
98819876
}
98829877

98839878
// If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check.
9884-
// also if HasImplicitReturnValue flags is not set this means that all codepaths in function body end with return of throw
9879+
// also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return or throw
98859880
if (nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block || !(func.flags & NodeFlags.HasImplicitReturn)) {
98869881
return;
98879882
}
98889883

9889-
if (!returnType || func.flags & NodeFlags.HasExplicitReturn) {
9890-
if (compilerOptions.noImplicitReturns) {
9891-
error(func.type || func, Diagnostics.Not_all_code_paths_return_a_value);
9892-
}
9893-
}
9894-
else {
9895-
// This function does not conform to the specification.
9896-
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
9884+
const hasExplicitReturn = func.flags & NodeFlags.HasExplicitReturn;
9885+
9886+
if (returnType && !hasExplicitReturn) {
9887+
// minimal check: function has syntactic return type annotation and no explicit return statements in the body
9888+
// this function does not conform to the specification.
9889+
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
98979890
error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value);
98989891
}
9892+
else if (compilerOptions.noImplicitReturns) {
9893+
if (!returnType) {
9894+
// If return type annotation is omitted check if function has any explicit return statements.
9895+
// If it does not have any - its inferred return type is void - don't do any checks.
9896+
// Otherwise get inferred return type from function body and report error only if it is not void / anytype
9897+
const inferredReturnType = hasExplicitReturn
9898+
? getReturnTypeOfSignature(getSignatureFromDeclaration(func))
9899+
: voidType;
9900+
9901+
if (inferredReturnType === voidType || isTypeAny(inferredReturnType)) {
9902+
return;
9903+
}
9904+
}
9905+
error(func.type || func, Diagnostics.Not_all_code_paths_return_a_value);
9906+
}
98999907
}
99009908

99019909
function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, contextualMapper?: TypeMapper): Type {
@@ -14376,6 +14384,7 @@ namespace ts {
1437614384
emitExtends = false;
1437714385
emitDecorate = false;
1437814386
emitParam = false;
14387+
emitAwaiter = false;
1437914388
potentialThisCollisions.length = 0;
1438014389

1438114390
forEach(node.statements, checkSourceElement);

src/compiler/emitter.ts

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5307,10 +5307,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53075307
function emitDecoratorsOfConstructor(node: ClassLikeDeclaration) {
53085308
const decorators = node.decorators;
53095309
const constructor = getFirstConstructorWithBody(node);
5310-
const hasDecoratedParameters = constructor && forEach(constructor.parameters, nodeIsDecorated);
5310+
const firstParameterDecorator = constructor && forEach(constructor.parameters, parameter => parameter.decorators);
53115311

53125312
// skip decoration of the constructor if neither it nor its parameters are decorated
5313-
if (!decorators && !hasDecoratedParameters) {
5313+
if (!decorators && !firstParameterDecorator) {
53145314
return;
53155315
}
53165316

@@ -5326,28 +5326,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53265326
//
53275327

53285328
writeLine();
5329-
emitStart(node);
5329+
emitStart(node.decorators || firstParameterDecorator);
53305330
emitDeclarationName(node);
53315331
write(" = __decorate([");
53325332
increaseIndent();
53335333
writeLine();
53345334

53355335
const decoratorCount = decorators ? decorators.length : 0;
5336-
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => {
5337-
emitStart(decorator);
5338-
emit(decorator.expression);
5339-
emitEnd(decorator);
5340-
});
5341-
5342-
argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0);
5336+
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true,
5337+
decorator => emit(decorator.expression));
5338+
if (firstParameterDecorator) {
5339+
argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0);
5340+
}
53435341
emitSerializedTypeMetadata(node, /*leadingComma*/ argumentsWritten >= 0);
53445342

53455343
decreaseIndent();
53465344
writeLine();
53475345
write("], ");
53485346
emitDeclarationName(node);
5349-
write(");");
5350-
emitEnd(node);
5347+
write(")");
5348+
emitEnd(node.decorators || firstParameterDecorator);
5349+
write(";");
53515350
writeLine();
53525351
}
53535352

@@ -5363,11 +5362,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53635362
continue;
53645363
}
53655364

5366-
// skip a member if it or any of its parameters are not decorated
5367-
if (!nodeOrChildIsDecorated(member)) {
5368-
continue;
5369-
}
5370-
53715365
// skip an accessor declaration if it is not the first accessor
53725366
let decorators: NodeArray<Decorator>;
53735367
let functionLikeMember: FunctionLikeDeclaration;
@@ -5394,6 +5388,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53945388
functionLikeMember = <MethodDeclaration>member;
53955389
}
53965390
}
5391+
const firstParameterDecorator = functionLikeMember && forEach(functionLikeMember.parameters, parameter => parameter.decorators);
5392+
5393+
// skip a member if it or any of its parameters are not decorated
5394+
if (!decorators && !firstParameterDecorator) {
5395+
continue;
5396+
}
53975397

53985398
// Emit the call to __decorate. Given the following:
53995399
//
@@ -5427,29 +5427,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
54275427
//
54285428

54295429
writeLine();
5430-
emitStart(member);
5430+
emitStart(decorators || firstParameterDecorator);
54315431
write("__decorate([");
54325432
increaseIndent();
54335433
writeLine();
54345434

54355435
const decoratorCount = decorators ? decorators.length : 0;
5436-
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => {
5437-
emitStart(decorator);
5438-
emit(decorator.expression);
5439-
emitEnd(decorator);
5440-
});
5436+
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true,
5437+
decorator => emit(decorator.expression));
54415438

5442-
argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0);
5439+
if (firstParameterDecorator) {
5440+
argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0);
5441+
}
54435442
emitSerializedTypeMetadata(member, argumentsWritten > 0);
54445443

54455444
decreaseIndent();
54465445
writeLine();
54475446
write("], ");
5448-
emitStart(member.name);
54495447
emitClassMemberPrefix(node, member);
54505448
write(", ");
54515449
emitExpressionForPropertyName(member.name);
5452-
emitEnd(member.name);
54535450

54545451
if (languageVersion > ScriptTarget.ES3) {
54555452
if (member.kind !== SyntaxKind.PropertyDeclaration) {
@@ -5464,8 +5461,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
54645461
}
54655462
}
54665463

5467-
write(");");
5468-
emitEnd(member);
5464+
write(")");
5465+
emitEnd(decorators || firstParameterDecorator);
5466+
write(";");
54695467
writeLine();
54705468
}
54715469
}
@@ -5478,11 +5476,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
54785476
if (nodeIsDecorated(parameter)) {
54795477
const decorators = parameter.decorators;
54805478
argumentsWritten += emitList(decorators, 0, decorators.length, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ leadingComma, /*noTrailingNewLine*/ true, decorator => {
5481-
emitStart(decorator);
54825479
write(`__param(${parameterIndex}, `);
54835480
emit(decorator.expression);
54845481
write(")");
5485-
emitEnd(decorator);
54865482
});
54875483
leadingComma = true;
54885484
}

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4902,7 +4902,7 @@ namespace ts {
49024902

49034903
if (!decorators) {
49044904
decorators = <NodeArray<Decorator>>[];
4905-
decorators.pos = scanner.getStartPos();
4905+
decorators.pos = decoratorStart;
49064906
}
49074907

49084908
const decorator = <Decorator>createNode(SyntaxKind.Decorator, decoratorStart);

src/compiler/sourcemap.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ namespace ts {
251251
}
252252

253253
function emitStart(range: TextRange) {
254-
emitPos(range.pos !== -1 ? skipTrivia(currentSourceFile.text, range.pos) : -1);
254+
const rangeHasDecorators = !!(range as Node).decorators;
255+
emitPos(range.pos !== -1 ? skipTrivia(currentSourceFile.text, rangeHasDecorators ? (range as Node).decorators.end : range.pos) : -1);
255256
}
256257

257258
function emitEnd(range: TextRange) {

src/compiler/utilities.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -906,23 +906,6 @@ namespace ts {
906906
return false;
907907
}
908908

909-
export function childIsDecorated(node: Node): boolean {
910-
switch (node.kind) {
911-
case SyntaxKind.ClassDeclaration:
912-
return forEach((<ClassDeclaration>node).members, nodeOrChildIsDecorated);
913-
914-
case SyntaxKind.MethodDeclaration:
915-
case SyntaxKind.SetAccessor:
916-
return forEach((<FunctionLikeDeclaration>node).parameters, nodeIsDecorated);
917-
}
918-
919-
return false;
920-
}
921-
922-
export function nodeOrChildIsDecorated(node: Node): boolean {
923-
return nodeIsDecorated(node) || childIsDecorated(node);
924-
}
925-
926909
export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression {
927910
return node.kind === SyntaxKind.PropertyAccessExpression;
928911
}

src/services/breakpoints.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace ts.BreakpointResolver {
1616

1717
let tokenAtLocation = getTokenAtPosition(sourceFile, position);
1818
let lineOfPosition = sourceFile.getLineAndCharacterOfPosition(position).line;
19-
if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart()).line > lineOfPosition) {
19+
if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart(sourceFile)).line > lineOfPosition) {
2020
// Get previous token if the token is returned starts on new line
2121
// eg: let x =10; |--- cursor is here
2222
// let y = 10;
@@ -39,16 +39,23 @@ namespace ts.BreakpointResolver {
3939
return spanInNode(tokenAtLocation);
4040

4141
function textSpan(startNode: Node, endNode?: Node) {
42-
return createTextSpanFromBounds(startNode.getStart(), (endNode || startNode).getEnd());
42+
const start = startNode.decorators ?
43+
skipTrivia(sourceFile.text, startNode.decorators.end) :
44+
startNode.getStart(sourceFile);
45+
return createTextSpanFromBounds(start, (endNode || startNode).getEnd());
4346
}
4447

4548
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {
46-
if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart()).line) {
49+
if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line) {
4750
return spanInNode(node);
4851
}
4952
return spanInNode(otherwiseOnNode);
5053
}
5154

55+
function spanInNodeArray<T>(nodeArray: NodeArray<T>) {
56+
return createTextSpanFromBounds(skipTrivia(sourceFile.text, nodeArray.pos), nodeArray.end);
57+
}
58+
5259
function spanInPreviousNode(node: Node): TextSpan {
5360
return spanInNode(findPrecedingToken(node.pos, sourceFile));
5461
}
@@ -65,6 +72,11 @@ namespace ts.BreakpointResolver {
6572
return spanInPreviousNode(node);
6673
}
6774

75+
if (node.parent.kind === SyntaxKind.Decorator) {
76+
// Set breakpoint on the decorator emit
77+
return spanInNode(node.parent);
78+
}
79+
6880
if (node.parent.kind === SyntaxKind.ForStatement) {
6981
// For now lets set the span on this expression, fix it later
7082
return textSpan(node);
@@ -207,6 +219,9 @@ namespace ts.BreakpointResolver {
207219
// span in statement
208220
return spanInNode((<WithStatement>node).statement);
209221

222+
case SyntaxKind.Decorator:
223+
return spanInNodeArray(node.parent.decorators);
224+
210225
// No breakpoint in interface, type alias
211226
case SyntaxKind.InterfaceDeclaration:
212227
case SyntaxKind.TypeAliasDeclaration:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [tests/cases/conformance/async/es6/asyncMultiFile.ts] ////
2+
3+
//// [a.ts]
4+
async function f() {}
5+
//// [b.ts]
6+
function g() { }
7+
8+
//// [a.js]
9+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {
10+
return new Promise(function (resolve, reject) {
11+
generator = generator.call(thisArg, _arguments);
12+
function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }
13+
function onfulfill(value) { try { step("next", value); } catch (e) { reject(e); } }
14+
function onreject(value) { try { step("throw", value); } catch (e) { reject(e); } }
15+
function step(verb, value) {
16+
var result = generator[verb](value);
17+
result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);
18+
}
19+
step("next", void 0);
20+
});
21+
};
22+
function f() {
23+
return __awaiter(this, void 0, Promise, function* () { });
24+
}
25+
//// [b.js]
26+
function g() { }
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/conformance/async/es6/a.ts ===
2+
async function f() {}
3+
>f : Symbol(f, Decl(a.ts, 0, 0))
4+
5+
=== tests/cases/conformance/async/es6/b.ts ===
6+
function g() { }
7+
>g : Symbol(g, Decl(b.ts, 0, 0))
8+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/conformance/async/es6/a.ts ===
2+
async function f() {}
3+
>f : () => Promise<void>
4+
5+
=== tests/cases/conformance/async/es6/b.ts ===
6+
function g() { }
7+
>g : () => void
8+

0 commit comments

Comments
 (0)