diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 5014c4241622e..06bdf81dd43dc 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -117,6 +117,12 @@ namespace ts { let labelIndexMap: Map; let implicitLabels: number[]; + // state used for emit helpers + let hasClassExtends: boolean; + let hasAsyncFunctions: boolean; + let hasDecorators: boolean; + let hasParameterDecorators: boolean; + // If this file is an external module, then it is automatically in strict-mode according to // ES6. If it is not an external module, then we'll determine if it is in strict mode or // not depending on if we see "use strict" in certain places (or if we hit a class/namespace). @@ -151,6 +157,10 @@ namespace ts { labelStack = undefined; labelIndexMap = undefined; implicitLabels = undefined; + hasClassExtends = false; + hasAsyncFunctions = false; + hasDecorators = false; + hasParameterDecorators = false; } return bindSourceFile; @@ -351,8 +361,8 @@ namespace ts { // when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope. // NOTE: Nested ambient modules always should go to to 'locals' table to prevent their automatic merge - // during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation - // and this case is specially handled. Module augmentations should only be merged with original module definition + // during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation + // and this case is specially handled. Module augmentations should only be merged with original module definition // and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed. if (!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) { const exportKind = @@ -429,6 +439,9 @@ namespace ts { // reset all reachability check related flags on node (for incremental scenarios) flags &= ~NodeFlags.ReachabilityCheckFlags; + // reset all emit helper flags on node (for incremental scenarios) + flags &= ~NodeFlags.EmitHelperFlags; + if (kind === SyntaxKind.InterfaceDeclaration) { seenThisKeyword = false; } @@ -459,6 +472,21 @@ namespace ts { flags = seenThisKeyword ? flags | NodeFlags.ContainsThis : flags & ~NodeFlags.ContainsThis; } + if (kind === SyntaxKind.SourceFile) { + if (hasClassExtends) { + flags |= NodeFlags.HasClassExtends; + } + if (hasDecorators) { + flags |= NodeFlags.HasDecorators; + } + if (hasParameterDecorators) { + flags |= NodeFlags.HasParamDecorators; + } + if (hasAsyncFunctions) { + flags |= NodeFlags.HasAsyncFunctions; + } + } + node.flags = flags; if (saveState) { @@ -1255,8 +1283,7 @@ namespace ts { return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Method | ((node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes); case SyntaxKind.FunctionDeclaration: - checkStrictModeFunctionName(node); - return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); + return bindFunctionDeclaration(node); case SyntaxKind.Constructor: return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None); case SyntaxKind.GetAccessor: @@ -1272,9 +1299,7 @@ namespace ts { return bindObjectLiteralExpression(node); case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - checkStrictModeFunctionName(node); - const bindingName = (node).name ? (node).name.text : "__function"; - return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName); + return bindFunctionExpression(node); case SyntaxKind.CallExpression: if (isInJavaScriptFile(node)) { @@ -1424,6 +1449,15 @@ namespace ts { } function bindClassLikeDeclaration(node: ClassLikeDeclaration) { + if (!isDeclarationFile(file) && !isInAmbientContext(node)) { + if (getClassExtendsHeritageClauseElement(node) !== undefined) { + hasClassExtends = true; + } + if (nodeIsDecorated(node)) { + hasDecorators = true; + } + } + if (node.kind === SyntaxKind.ClassDeclaration) { bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes); } @@ -1493,6 +1527,13 @@ namespace ts { } function bindParameter(node: ParameterDeclaration) { + if (!isDeclarationFile(file) && + !isInAmbientContext(node) && + nodeIsDecorated(node)) { + hasDecorators = true; + hasParameterDecorators = true; + } + if (inStrictMode) { // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) @@ -1514,7 +1555,39 @@ namespace ts { } } + function bindFunctionDeclaration(node: FunctionDeclaration) { + if (!isDeclarationFile(file) && !isInAmbientContext(node)) { + if (isAsyncFunctionLike(node)) { + hasAsyncFunctions = true; + } + } + + checkStrictModeFunctionName(node); + return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); + } + + function bindFunctionExpression(node: FunctionExpression) { + if (!isDeclarationFile(file) && !isInAmbientContext(node)) { + if (isAsyncFunctionLike(node)) { + hasAsyncFunctions = true; + } + } + + checkStrictModeFunctionName(node); + const bindingName = (node).name ? (node).name.text : "__function"; + return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName); + } + function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) { + if (!isDeclarationFile(file) && !isInAmbientContext(node)) { + if (isAsyncFunctionLike(node)) { + hasAsyncFunctions = true; + } + if (nodeIsDecorated(node)) { + hasDecorators = true; + } + } + return hasDynamicName(node) ? bindAnonymousDeclaration(node, symbolFlags, "__computed") : declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ddb49a2d8f87e..edc1868401d5b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -174,11 +174,6 @@ namespace ts { const unionTypes: Map = {}; const intersectionTypes: Map = {}; const stringLiteralTypes: Map = {}; - let emitExtends = false; - let emitDecorate = false; - let emitParam = false; - let emitAwaiter = false; - const emitGenerator = false; const resolutionTargets: TypeSystemEntity[] = []; const resolutionResults: boolean[] = []; @@ -458,7 +453,7 @@ namespace ts { * Get symbols that represent parameter-property-declaration as parameter and as property declaration * @param parameter a parameterDeclaration node * @param parameterName a name of the parameter to get the symbols for. - * @return a tuple of two symbols + * @return a tuple of two symbols */ function getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): [Symbol, Symbol] { const constructoDeclaration = parameter.parent; @@ -10249,11 +10244,6 @@ namespace ts { return anyFunctionType; } - const isAsync = isAsyncFunctionLike(node); - if (isAsync) { - emitAwaiter = true; - } - const links = getNodeLinks(node); const type = getTypeOfSymbol(node.symbol); const contextSensitive = isContextSensitive(node); @@ -10302,10 +10292,6 @@ namespace ts { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const isAsync = isAsyncFunctionLike(node); - if (isAsync) { - emitAwaiter = true; - } - const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type)); if (!node.asteriskToken) { // return is not necessary in the body of generators @@ -12442,11 +12428,6 @@ namespace ts { } } - emitDecorate = true; - if (node.kind === SyntaxKind.Parameter) { - emitParam = true; - } - forEach(node.decorators, checkDecorator); } @@ -12464,9 +12445,6 @@ namespace ts { checkDecorators(node); checkSignatureDeclaration(node); const isAsync = isAsyncFunctionLike(node); - if (isAsync) { - emitAwaiter = true; - } // Do not use hasDynamicName here, because that returns false for well known symbols. // We want to perform checkComputedPropertyName for all computed properties, including @@ -13597,7 +13575,6 @@ namespace ts { const baseTypeNode = getClassExtendsHeritageClauseElement(node); if (baseTypeNode) { - emitExtends = emitExtends || !isInAmbientContext(node); const baseTypes = getBaseTypes(type); if (baseTypes.length && produceDiagnostics) { const baseType = baseTypes[0]; @@ -14777,10 +14754,6 @@ namespace ts { // Grammar checking checkGrammarSourceFile(node); - emitExtends = false; - emitDecorate = false; - emitParam = false; - emitAwaiter = false; potentialThisCollisions.length = 0; deferredNodes = []; @@ -14797,26 +14770,6 @@ namespace ts { potentialThisCollisions.length = 0; } - if (emitExtends) { - links.flags |= NodeCheckFlags.EmitExtends; - } - - if (emitDecorate) { - links.flags |= NodeCheckFlags.EmitDecorate; - } - - if (emitParam) { - links.flags |= NodeCheckFlags.EmitParam; - } - - if (emitAwaiter) { - links.flags |= NodeCheckFlags.EmitAwaiter; - } - - if (emitGenerator || (emitAwaiter && languageVersion < ScriptTarget.ES6)) { - links.flags |= NodeCheckFlags.EmitGenerator; - } - links.flags |= NodeCheckFlags.TypeChecked; } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 05983f72dcb0c..44cb0ea3ccfe1 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -7349,12 +7349,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge if (!compilerOptions.noEmitHelpers) { // Only Emit __extends function when target ES5. // For target ES6 and above, we can emit classDeclaration as is. - if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitExtends)) { + if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && node.flags & NodeFlags.HasClassExtends)) { writeLines(extendsHelper); extendsEmitted = true; } - if (!decorateEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitDecorate) { + if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) { writeLines(decorateHelper); if (compilerOptions.emitDecoratorMetadata) { writeLines(metadataHelper); @@ -7362,12 +7362,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge decorateEmitted = true; } - if (!paramEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitParam) { + if (!paramEmitted && node.flags & NodeFlags.HasParamDecorators) { writeLines(paramHelper); paramEmitted = true; } - if (!awaiterEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitAwaiter) { + if (!awaiterEmitted && node.flags & NodeFlags.HasAsyncFunctions) { writeLines(awaiterHelper); awaiterEmitted = true; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 74c1af6ae521f..18dc6602abe70 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -391,11 +391,17 @@ namespace ts { HasImplicitReturn = 1 << 19, // If function implicitly returns on one of codepaths (initialized by binding) HasExplicitReturn = 1 << 20, // If function has explicit reachable return on one of codepaths (initialized by binding) GlobalAugmentation = 1 << 21, // Set if module declaration is an augmentation for the global scope + HasClassExtends = 1 << 22, // If the file has a non-ambient class with an extends clause in ES5 or lower (initialized by binding) + HasDecorators = 1 << 23, // If the file has decorators (initialized by binding) + HasParamDecorators = 1 << 24, // If the file has parameter decorators (initialized by binding) + HasAsyncFunctions = 1 << 25, // If the file has async functions (initialized by binding) + Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async, AccessibilityModifier = Public | Private | Protected, BlockScoped = Let | Const, - ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn + ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn, + EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions, } /* @internal */ @@ -2047,11 +2053,6 @@ namespace ts { TypeChecked = 0x00000001, // Node has been type checked LexicalThis = 0x00000002, // Lexical 'this' reference CaptureThis = 0x00000004, // Lexical 'this' used in body - EmitExtends = 0x00000008, // Emit __extends - EmitDecorate = 0x00000010, // Emit __decorate - EmitParam = 0x00000020, // Emit __param helper for decorators - EmitAwaiter = 0x00000040, // Emit __awaiter - EmitGenerator = 0x00000080, // Emit __generator SuperInstance = 0x00000100, // Instance 'super' reference SuperStatic = 0x00000200, // Static 'super' reference ContextChecked = 0x00000400, // Contextual types have been assigned diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 69941a6095dc4..4636c8d144cf4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -802,8 +802,8 @@ namespace ts { } /** - * Given an super call\property node returns a closest node where either - * - super call\property is legal in the node and not legal in the parent node the node. + * Given an super call\property node returns a closest node where either + * - super call\property is legal in the node and not legal in the parent node the node. * i.e. super call is legal in constructor but not legal in the class body. * - node is arrow function (so caller might need to call getSuperContainer in case it needs to climb higher) * - super call\property is definitely illegal in the node (but might be legal in some subnode) @@ -885,54 +885,28 @@ namespace ts { // property declarations are valid if their parent is a class declaration. return node.parent.kind === SyntaxKind.ClassDeclaration; - case SyntaxKind.Parameter: - // if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target; - return (node.parent).body && node.parent.parent.kind === SyntaxKind.ClassDeclaration; - case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.MethodDeclaration: // if this method has a body and its parent is a class declaration, this is a valid target. - return (node).body && node.parent.kind === SyntaxKind.ClassDeclaration; + return (node).body !== undefined + && node.parent.kind === SyntaxKind.ClassDeclaration; + + case SyntaxKind.Parameter: + // if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target; + return (node.parent).body !== undefined + && (node.parent.kind === SyntaxKind.Constructor + || node.parent.kind === SyntaxKind.MethodDeclaration + || node.parent.kind === SyntaxKind.SetAccessor) + && node.parent.parent.kind === SyntaxKind.ClassDeclaration; } return false; } export function nodeIsDecorated(node: Node): boolean { - switch (node.kind) { - case SyntaxKind.ClassDeclaration: - if (node.decorators) { - return true; - } - - return false; - - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.Parameter: - if (node.decorators) { - return true; - } - - return false; - - case SyntaxKind.GetAccessor: - if ((node).body && node.decorators) { - return true; - } - - return false; - - case SyntaxKind.MethodDeclaration: - case SyntaxKind.SetAccessor: - if ((node).body && node.decorators) { - return true; - } - - return false; - } - - return false; + return node.decorators !== undefined + && nodeCanBeDecorated(node); } export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression { diff --git a/tests/baselines/reference/asyncFunctionsAcrossFiles.js b/tests/baselines/reference/asyncFunctionsAcrossFiles.js new file mode 100644 index 0000000000000..05b8ca564217f --- /dev/null +++ b/tests/baselines/reference/asyncFunctionsAcrossFiles.js @@ -0,0 +1,47 @@ +//// [tests/cases/compiler/asyncFunctionsAcrossFiles.ts] //// + +//// [a.ts] +import { b } from './b'; +export const a = { + f: async () => { + await b.f(); + } +}; +//// [b.ts] +import { a } from './a'; +export const b = { + f: async () => { + await a.f(); + } +}; + +//// [b.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new P(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.call(thisArg, _arguments)).next()); + }); +}; +import { a } from './a'; +export const b = { + f: () => __awaiter(this, void 0, Promise, function* () { + yield a.f(); + }) +}; +//// [a.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new P(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.call(thisArg, _arguments)).next()); + }); +}; +import { b } from './b'; +export const a = { + f: () => __awaiter(this, void 0, Promise, function* () { + yield b.f(); + }) +}; diff --git a/tests/baselines/reference/asyncFunctionsAcrossFiles.symbols b/tests/baselines/reference/asyncFunctionsAcrossFiles.symbols new file mode 100644 index 0000000000000..2e9c52d5d91d5 --- /dev/null +++ b/tests/baselines/reference/asyncFunctionsAcrossFiles.symbols @@ -0,0 +1,32 @@ +=== tests/cases/compiler/a.ts === +import { b } from './b'; +>b : Symbol(b, Decl(a.ts, 0, 8)) + +export const a = { +>a : Symbol(a, Decl(a.ts, 1, 12)) + + f: async () => { +>f : Symbol(f, Decl(a.ts, 1, 18)) + + await b.f(); +>b.f : Symbol(f, Decl(b.ts, 1, 18)) +>b : Symbol(b, Decl(a.ts, 0, 8)) +>f : Symbol(f, Decl(b.ts, 1, 18)) + } +}; +=== tests/cases/compiler/b.ts === +import { a } from './a'; +>a : Symbol(a, Decl(b.ts, 0, 8)) + +export const b = { +>b : Symbol(b, Decl(b.ts, 1, 12)) + + f: async () => { +>f : Symbol(f, Decl(b.ts, 1, 18)) + + await a.f(); +>a.f : Symbol(f, Decl(a.ts, 1, 18)) +>a : Symbol(a, Decl(b.ts, 0, 8)) +>f : Symbol(f, Decl(a.ts, 1, 18)) + } +}; diff --git a/tests/baselines/reference/asyncFunctionsAcrossFiles.types b/tests/baselines/reference/asyncFunctionsAcrossFiles.types new file mode 100644 index 0000000000000..0b94614154189 --- /dev/null +++ b/tests/baselines/reference/asyncFunctionsAcrossFiles.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/a.ts === +import { b } from './b'; +>b : { f: () => Promise; } + +export const a = { +>a : { f: () => Promise; } +>{ f: async () => { await b.f(); }} : { f: () => Promise; } + + f: async () => { +>f : () => Promise +>async () => { await b.f(); } : () => Promise + + await b.f(); +>await b.f() : void +>b.f() : Promise +>b.f : () => Promise +>b : { f: () => Promise; } +>f : () => Promise + } +}; +=== tests/cases/compiler/b.ts === +import { a } from './a'; +>a : { f: () => Promise; } + +export const b = { +>b : { f: () => Promise; } +>{ f: async () => { await a.f(); }} : { f: () => Promise; } + + f: async () => { +>f : () => Promise +>async () => { await a.f(); } : () => Promise + + await a.f(); +>await a.f() : void +>a.f() : Promise +>a.f : () => Promise +>a : { f: () => Promise; } +>f : () => Promise + } +}; diff --git a/tests/baselines/reference/classExtendsAcrossFiles.js b/tests/baselines/reference/classExtendsAcrossFiles.js new file mode 100644 index 0000000000000..b533b880036f3 --- /dev/null +++ b/tests/baselines/reference/classExtendsAcrossFiles.js @@ -0,0 +1,71 @@ +//// [tests/cases/compiler/classExtendsAcrossFiles.ts] //// + +//// [a.ts] +import { b } from './b'; +export const a = { + f: () => { + class A { } + class B extends A { } + b.f(); + } +}; +//// [b.ts] +import { a } from './a'; +export const b = { + f: () => { + class A { } + class B extends A { } + a.f(); + } +}; + +//// [b.js] +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var a_1 = require('./a'); +exports.b = { + f: function () { + var A = (function () { + function A() { + } + return A; + }()); + var B = (function (_super) { + __extends(B, _super); + function B() { + _super.apply(this, arguments); + } + return B; + }(A)); + a_1.a.f(); + } +}; +//// [a.js] +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var b_1 = require('./b'); +exports.a = { + f: function () { + var A = (function () { + function A() { + } + return A; + }()); + var B = (function (_super) { + __extends(B, _super); + function B() { + _super.apply(this, arguments); + } + return B; + }(A)); + b_1.b.f(); + } +}; diff --git a/tests/baselines/reference/classExtendsAcrossFiles.symbols b/tests/baselines/reference/classExtendsAcrossFiles.symbols new file mode 100644 index 0000000000000..cf81c9239122d --- /dev/null +++ b/tests/baselines/reference/classExtendsAcrossFiles.symbols @@ -0,0 +1,46 @@ +=== tests/cases/compiler/a.ts === +import { b } from './b'; +>b : Symbol(b, Decl(a.ts, 0, 8)) + +export const a = { +>a : Symbol(a, Decl(a.ts, 1, 12)) + + f: () => { +>f : Symbol(f, Decl(a.ts, 1, 18)) + + class A { } +>A : Symbol(A, Decl(a.ts, 2, 14)) + + class B extends A { } +>B : Symbol(B, Decl(a.ts, 3, 19)) +>A : Symbol(A, Decl(a.ts, 2, 14)) + + b.f(); +>b.f : Symbol(f, Decl(b.ts, 1, 18)) +>b : Symbol(b, Decl(a.ts, 0, 8)) +>f : Symbol(f, Decl(b.ts, 1, 18)) + } +}; +=== tests/cases/compiler/b.ts === +import { a } from './a'; +>a : Symbol(a, Decl(b.ts, 0, 8)) + +export const b = { +>b : Symbol(b, Decl(b.ts, 1, 12)) + + f: () => { +>f : Symbol(f, Decl(b.ts, 1, 18)) + + class A { } +>A : Symbol(A, Decl(b.ts, 2, 14)) + + class B extends A { } +>B : Symbol(B, Decl(b.ts, 3, 19)) +>A : Symbol(A, Decl(b.ts, 2, 14)) + + a.f(); +>a.f : Symbol(f, Decl(a.ts, 1, 18)) +>a : Symbol(a, Decl(b.ts, 0, 8)) +>f : Symbol(f, Decl(a.ts, 1, 18)) + } +}; diff --git a/tests/baselines/reference/classExtendsAcrossFiles.types b/tests/baselines/reference/classExtendsAcrossFiles.types new file mode 100644 index 0000000000000..fe3427ba04332 --- /dev/null +++ b/tests/baselines/reference/classExtendsAcrossFiles.types @@ -0,0 +1,52 @@ +=== tests/cases/compiler/a.ts === +import { b } from './b'; +>b : { f: () => void; } + +export const a = { +>a : { f: () => void; } +>{ f: () => { class A { } class B extends A { } b.f(); }} : { f: () => void; } + + f: () => { +>f : () => void +>() => { class A { } class B extends A { } b.f(); } : () => void + + class A { } +>A : A + + class B extends A { } +>B : B +>A : A + + b.f(); +>b.f() : void +>b.f : () => void +>b : { f: () => void; } +>f : () => void + } +}; +=== tests/cases/compiler/b.ts === +import { a } from './a'; +>a : { f: () => void; } + +export const b = { +>b : { f: () => void; } +>{ f: () => { class A { } class B extends A { } a.f(); }} : { f: () => void; } + + f: () => { +>f : () => void +>() => { class A { } class B extends A { } a.f(); } : () => void + + class A { } +>A : A + + class B extends A { } +>B : B +>A : A + + a.f(); +>a.f() : void +>a.f : () => void +>a : { f: () => void; } +>f : () => void + } +}; diff --git a/tests/cases/compiler/asyncFunctionsAcrossFiles.ts b/tests/cases/compiler/asyncFunctionsAcrossFiles.ts new file mode 100644 index 0000000000000..c5f6a220fd854 --- /dev/null +++ b/tests/cases/compiler/asyncFunctionsAcrossFiles.ts @@ -0,0 +1,15 @@ +// @target: es6 +// @filename: a.ts +import { b } from './b'; +export const a = { + f: async () => { + await b.f(); + } +}; +// @filename: b.ts +import { a } from './a'; +export const b = { + f: async () => { + await a.f(); + } +}; \ No newline at end of file diff --git a/tests/cases/compiler/classExtendsAcrossFiles.ts b/tests/cases/compiler/classExtendsAcrossFiles.ts new file mode 100644 index 0000000000000..14e227647e7d7 --- /dev/null +++ b/tests/cases/compiler/classExtendsAcrossFiles.ts @@ -0,0 +1,20 @@ +// @target: es5 +// @module: commonjs +// @filename: a.ts +import { b } from './b'; +export const a = { + f: () => { + class A { } + class B extends A { } + b.f(); + } +}; +// @filename: b.ts +import { a } from './a'; +export const b = { + f: () => { + class A { } + class B extends A { } + a.f(); + } +}; \ No newline at end of file