diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4b1ab123051..af910558655 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22875,24 +22875,29 @@ namespace ts { // If the symbol of the node has members, treat it like a constructor. const symbol = getSymbolOfNode(func); - return !!symbol && symbol.members !== undefined; + return !!symbol && hasEntries(symbol.members); } return false; } function mergeJSSymbols(target: Symbol, source: Symbol | undefined) { if (source && (hasEntries(source.exports) || hasEntries(source.members))) { - target = cloneSymbol(target); - if (hasEntries(source.exports)) { - target.exports = target.exports || createSymbolTable(); - mergeSymbolTable(target.exports, source.exports); + const links = getSymbolLinks(source); + if (!links.inferredClassSymbol || !links.inferredClassSymbol.has("" + getSymbolId(target))) { + const inferred = isTransientSymbol(target) ? target : cloneSymbol(target) as TransientSymbol; + inferred.exports = inferred.exports || createSymbolTable(); + inferred.members = inferred.members || createSymbolTable(); + inferred.flags |= source.flags & SymbolFlags.Class; + if (hasEntries(source.exports)) { + mergeSymbolTable(inferred.exports, source.exports); + } + if (hasEntries(source.members)) { + mergeSymbolTable(inferred.members, source.members); + } + (links.inferredClassSymbol || (links.inferredClassSymbol = createMap())).set("" + getSymbolId(inferred), inferred); + return inferred; } - if (hasEntries(source.members)) { - target.members = target.members || createSymbolTable(); - mergeSymbolTable(target.members, source.members); - } - target.flags |= source.flags & SymbolFlags.Class; - return target as TransientSymbol; + return links.inferredClassSymbol.get("" + getSymbolId(target)); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c9d97b91185..e5fd7575625 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3792,30 +3792,31 @@ namespace ts { /* @internal */ export interface SymbolLinks { - immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead. - target?: Symbol; // Resolved (non-alias) target of an alias - type?: Type; // Type of value symbol - uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol - declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter - resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference - typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic) - outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type - instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) - mapper?: TypeMapper; // Type mapper for instantiation alias - referenced?: boolean; // True if alias symbol has been referenced as a value - containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property - leftSpread?: Symbol; // Left source for synthetic spread property - rightSpread?: Symbol; // Right source for synthetic spread property - syntheticOrigin?: Symbol; // For a property on a mapped or spread type, points back to the original property - isDiscriminantProperty?: boolean; // True if discriminant synthetic property - resolvedExports?: SymbolTable; // Resolved exports of module or combined early- and late-bound static members of a class. - resolvedMembers?: SymbolTable; // Combined early- and late-bound members of a symbol - exportsChecked?: boolean; // True if exports of external module have been checked - typeParametersChecked?: boolean; // True if type parameters of merged class and interface declarations have been checked. + immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead. + target?: Symbol; // Resolved (non-alias) target of an alias + type?: Type; // Type of value symbol + uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol + declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter + resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference + typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic) + outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type + instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) + inferredClassSymbol?: Map; // Symbol of an inferred ES5 constructor function + mapper?: TypeMapper; // Type mapper for instantiation alias + referenced?: boolean; // True if alias symbol has been referenced as a value + containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property + leftSpread?: Symbol; // Left source for synthetic spread property + rightSpread?: Symbol; // Right source for synthetic spread property + syntheticOrigin?: Symbol; // For a property on a mapped or spread type, points back to the original property + isDiscriminantProperty?: boolean; // True if discriminant synthetic property + resolvedExports?: SymbolTable; // Resolved exports of module or combined early- and late-bound static members of a class. + resolvedMembers?: SymbolTable; // Combined early- and late-bound members of a symbol + exportsChecked?: boolean; // True if exports of external module have been checked + typeParametersChecked?: boolean; // True if type parameters of merged class and interface declarations have been checked. isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration - bindingElement?: BindingElement; // Binding element associated with property symbol - exportsSomeValue?: boolean; // True if module exports some value (not just types) - enumKind?: EnumKind; // Enum declaration classification + bindingElement?: BindingElement; // Binding element associated with property symbol + exportsSomeValue?: boolean; // True if module exports some value (not just types) + enumKind?: EnumKind; // Enum declaration classification originatingImport?: ImportDeclaration | ImportCall; // Import declaration which produced the symbol, present if the symbol is marked as uncallable but had call signatures in `resolveESModuleSymbol` lateSymbol?: Symbol; // Late-bound symbol for a computed property specifierCache?: Map; // For symbols corresponding to external modules, a cache of incoming path -> module specifier name mappings diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 35879b6615c..79e9f73d205 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2577,7 +2577,7 @@ - + diff --git a/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts b/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts index e6e8d759c60..c70de503303 100644 --- a/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts +++ b/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts @@ -14,7 +14,7 @@ namespace ts.codefix { function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { const token = getTokenAtPosition(sourceFile, pos); - const assertion = Debug.assertDefined(findAncestor(token, (n): n is AsExpression | TypeAssertion => isAsExpression(n) || isTypeAssertion(n))); + const assertion = Debug.assertDefined(findAncestor(token, (n): n is AsExpression | TypeAssertion => isAsExpression(n) || isTypeAssertion(n)), "Expected to find an assertion expression"); const replacement = isAsExpression(assertion) ? createAsExpression(assertion.expression, createKeywordTypeNode(SyntaxKind.UnknownKeyword)) : createTypeAssertion(createKeywordTypeNode(SyntaxKind.UnknownKeyword), assertion.expression); diff --git a/src/services/codefixes/annotateWithTypeFromJSDoc.ts b/src/services/codefixes/annotateWithTypeFromJSDoc.ts index c3143921106..3428a60201f 100644 --- a/src/services/codefixes/annotateWithTypeFromJSDoc.ts +++ b/src/services/codefixes/annotateWithTypeFromJSDoc.ts @@ -60,8 +60,8 @@ namespace ts.codefix { } } else { - const jsdocType = Debug.assertDefined(getJSDocType(decl)); // If not defined, shouldn't have been an error to fix - Debug.assert(!decl.type); // If defined, shouldn't have been an error to fix. + const jsdocType = Debug.assertDefined(getJSDocType(decl), "A JSDocType for this declaration should exist"); // If not defined, shouldn't have been an error to fix + Debug.assert(!decl.type, "The JSDocType decl should have a type"); // If defined, shouldn't have been an error to fix. changes.tryInsertTypeAnnotation(sourceFile, decl, transformJSDocType(jsdocType)); } } diff --git a/src/services/codefixes/convertToEs6Module.ts b/src/services/codefixes/convertToEs6Module.ts index 72f7e0c005f..25c42288355 100644 --- a/src/services/codefixes/convertToEs6Module.ts +++ b/src/services/codefixes/convertToEs6Module.ts @@ -178,7 +178,7 @@ namespace ts.codefix { // `const a = require("b").c` --> `import { c as a } from "./b"; return [makeSingleImport(name.text, propertyName, moduleSpecifier, quotePreference)]; default: - return Debug.assertNever(name); + return Debug.assertNever(name, `Convert to ES6 module got invalid syntax form ${(name as BindingName).kind}`); } } @@ -239,7 +239,7 @@ namespace ts.codefix { case SyntaxKind.MethodDeclaration: return !isIdentifier(prop.name) ? undefined : functionExpressionToDeclaration(prop.name.text, [createToken(SyntaxKind.ExportKeyword)], prop); default: - Debug.assertNever(prop); + Debug.assertNever(prop, `Convert to ES6 got invalid prop kind ${(prop as ObjectLiteralElementLike).kind}`); } }); return statements && [statements, false]; @@ -377,7 +377,7 @@ namespace ts.codefix { case SyntaxKind.Identifier: return convertSingleIdentifierImport(file, name, moduleSpecifier, changes, checker, identifiers, quotePreference); default: - return Debug.assertNever(name); + return Debug.assertNever(name, `Convert to ES6 module got invalid name kind ${(name as BindingName).kind}`); } } @@ -401,7 +401,7 @@ namespace ts.codefix { const { parent } = use; if (isPropertyAccessExpression(parent)) { const { expression, name: { text: propertyName } } = parent; - Debug.assert(expression === use); // Else shouldn't have been in `collectIdentifiers` + Debug.assert(expression === use, "Didn't expect expression === use"); // Else shouldn't have been in `collectIdentifiers` let idName = namedBindingsNames.get(propertyName); if (idName === undefined) { idName = makeUniqueName(propertyName, identifiers); diff --git a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts index b382b9a2f05..b5d107398d8 100644 --- a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts +++ b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts @@ -19,8 +19,8 @@ namespace ts.codefix { function getImportTypeNode(sourceFile: SourceFile, pos: number): ImportTypeNode { const token = getTokenAtPosition(sourceFile, pos); - Debug.assert(token.kind === SyntaxKind.ImportKeyword); - Debug.assert(token.parent.kind === SyntaxKind.ImportType); + Debug.assert(token.kind === SyntaxKind.ImportKeyword, "This token should be an ImportKeyword"); + Debug.assert(token.parent.kind === SyntaxKind.ImportType, "Token parent should be an ImportType"); return token.parent; } diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index d164623b8ee..695e71b53c2 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -30,7 +30,7 @@ namespace ts.codefix { }); function getClass(sourceFile: SourceFile, pos: number): ClassLikeDeclaration { - return Debug.assertDefined(getContainingClass(getTokenAtPosition(sourceFile, pos))); + return Debug.assertDefined(getContainingClass(getTokenAtPosition(sourceFile, pos)), "There should be a containing class"); } function symbolPointsToNonPrivateMember (symbol: Symbol) { diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts index 7d021d5e260..4fb14545a20 100644 --- a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -17,7 +17,7 @@ namespace ts.codefix { function getNode(sourceFile: SourceFile, pos: number): ConstructorDeclaration { const token = getTokenAtPosition(sourceFile, pos); - Debug.assert(token.kind === SyntaxKind.ConstructorKeyword); + Debug.assert(token.kind === SyntaxKind.ConstructorKeyword, "token should be at the constructor keyword"); return token.parent as ConstructorDeclaration; } diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index 5dd57b6c454..5bd57fb8fc9 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -36,12 +36,12 @@ namespace ts.codefix { let suggestion: string | undefined; if (isPropertyAccessExpression(node.parent) && node.parent.name === node) { - Debug.assert(node.kind === SyntaxKind.Identifier); + Debug.assert(node.kind === SyntaxKind.Identifier, "Expected an identifier for spelling (property access)"); const containingType = checker.getTypeAtLocation(node.parent.expression); suggestion = checker.getSuggestionForNonexistentProperty(node as Identifier, containingType); } else if (isImportSpecifier(node.parent) && node.parent.name === node) { - Debug.assert(node.kind === SyntaxKind.Identifier); + Debug.assert(node.kind === SyntaxKind.Identifier, "Expected an identifier for spelling (import)"); const importDeclaration = findAncestor(node, isImportDeclaration)!; const resolvedSourceFile = getResolvedSourceFileFromImportDeclaration(sourceFile, context, importDeclaration); if (resolvedSourceFile && resolvedSourceFile.symbol) { diff --git a/src/services/codefixes/fixUnreachableCode.ts b/src/services/codefixes/fixUnreachableCode.ts index 2d45de950b1..c8cd5650969 100644 --- a/src/services/codefixes/fixUnreachableCode.ts +++ b/src/services/codefixes/fixUnreachableCode.ts @@ -15,7 +15,7 @@ namespace ts.codefix { function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number, length: number): void { const token = getTokenAtPosition(sourceFile, start); const statement = findAncestor(token, isStatement)!; - Debug.assert(statement.getStart(sourceFile) === token.getStart(sourceFile)); + Debug.assert(statement.getStart(sourceFile) === token.getStart(sourceFile), "token and statement should start at the same point"); const container = (isBlock(statement.parent) ? statement.parent : statement).parent; if (!isBlock(statement.parent) || statement === first(statement.parent.statements)) { @@ -40,7 +40,7 @@ namespace ts.codefix { if (isBlock(statement.parent)) { const end = start + length; - const lastStatement = Debug.assertDefined(lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end)); + const lastStatement = Debug.assertDefined(lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end), "Some statement should be last"); changes.deleteNodeRange(sourceFile, statement, lastStatement); } else { diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 059c8194f8e..316142df0b6 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -117,7 +117,7 @@ namespace ts.codefix { } function deleteTypeParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void { - changes.delete(sourceFile, Debug.assertDefined(cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters)); + changes.delete(sourceFile, Debug.assertDefined(cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters, "The type parameter to delete should exist")); } // Sometimes the diagnostic span is an entire ImportDeclaration, so we should remove the whole thing. @@ -231,7 +231,7 @@ namespace ts.codefix { // Can't remove a non-last parameter in a callback. Can remove a parameter in code-fix-all if future parameters are also unused. const { parameters } = parent; const index = parameters.indexOf(p); - Debug.assert(index !== -1); + Debug.assert(index !== -1, "The parameter should already be in the list"); return isFixAll ? parameters.slice(index + 1).every(p => p.name.kind === SyntaxKind.Identifier && !p.symbol.isReferenced) : index === parameters.length - 1; diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 15e26936e5d..307e49c0c44 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -87,7 +87,7 @@ namespace ts.codefix { ambient ? undefined : createStubbedMethodBody(preferences))); } else { - Debug.assertNode(accessor, isSetAccessorDeclaration); + Debug.assertNode(accessor, isSetAccessorDeclaration, "The counterpart to a getter should be a setter"); const parameter = getSetAccessorValueParameter(accessor); const parameterName = parameter && isIdentifier(parameter.name) ? idText(parameter.name) : undefined; out(createSetAccessor( @@ -115,7 +115,7 @@ namespace ts.codefix { } if (declarations.length === 1) { - Debug.assert(signatures.length === 1); + Debug.assert(signatures.length === 1, "One declaration implies one signature"); const signature = signatures[0]; outputMethod(signature, modifiers, name, ambient ? undefined : createStubbedMethodBody(preferences)); break; @@ -132,7 +132,7 @@ namespace ts.codefix { outputMethod(signature, modifiers, name, createStubbedMethodBody(preferences)); } else { - Debug.assert(declarations.length === signatures.length); + Debug.assert(declarations.length === signatures.length, "Declarations and signatures should match count"); out(createMethodImplementingSignatures(signatures, name, optional, modifiers, preferences)); } } diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 248f34065a5..4ae8b3466fb 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -57,7 +57,7 @@ namespace ts.codefix { pushIfUnique(entry.namedImports, symbolName); } else { - Debug.assert(entry.defaultImport === undefined || entry.defaultImport === symbolName); + Debug.assert(entry.defaultImport === undefined || entry.defaultImport === symbolName, "(Add to Existing) Default import should be missing or match symbolName"); entry.defaultImport = symbolName; } break; @@ -70,7 +70,7 @@ namespace ts.codefix { } switch (importKind) { case ImportKind.Default: - Debug.assert(entry.defaultImport === undefined || entry.defaultImport === symbolName); + Debug.assert(entry.defaultImport === undefined || entry.defaultImport === symbolName, "(Add new) Default import should be missing or match symbolName"); entry.defaultImport = symbolName; break; case ImportKind.Named: @@ -78,14 +78,14 @@ namespace ts.codefix { break; case ImportKind.Equals: case ImportKind.Namespace: - Debug.assert(entry.namespaceLikeImport === undefined || entry.namespaceLikeImport.name === symbolName); + Debug.assert(entry.namespaceLikeImport === undefined || entry.namespaceLikeImport.name === symbolName, "Namespacelike import shoudl be missing or match symbolName"); entry.namespaceLikeImport = { importKind, name: symbolName }; break; } break; } default: - Debug.assertNever(fix); + Debug.assertNever(fix, `fix wasn't never - got kind ${(fix as ImportFix).kind}`); } }); @@ -165,7 +165,7 @@ namespace ts.codefix { preferences: UserPreferences, ): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } { const exportInfos = getAllReExportingModules(sourceFile, exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles()); - Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol)); + Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol), "Some exportInfo should match the specified moduleSymbol"); // We sort the best codefixes first, so taking `first` is best for completions. const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences)).moduleSpecifier; const fix = first(getFixForImport(exportInfos, symbolName, position, program, sourceFile, host, preferences)); @@ -288,7 +288,7 @@ namespace ts.codefix { moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap) .map((moduleSpecifier): FixAddNewImport | FixUseImportType => // `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types. - exportedSymbolIsTypeOnly && isJs ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position) } : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind })); + exportedSymbolIsTypeOnly && isJs ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position, "position should be defined") } : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind })); // Sort to keep the shortest paths first return sort(choicesForEachExportingModule, (a, b) => a.moduleSpecifier.length - b.moduleSpecifier.length); } @@ -369,7 +369,7 @@ namespace ts.codefix { // Fall back to the `import * as ns` style import. return ImportKind.Namespace; default: - return Debug.assertNever(moduleKind); + return Debug.assertNever(moduleKind, `Unexpected moduleKind ${moduleKind}`); } } @@ -382,7 +382,7 @@ namespace ts.codefix { ? checker.getJsxNamespace(sourceFile) : symbolToken.text; // "default" is a keyword and not a legal identifier for the import, so we don't expect it here - Debug.assert(symbolName !== InternalSymbolName.Default); + Debug.assert(symbolName !== InternalSymbolName.Default, "'default' isn't a legal identifier and couldn't occur here"); const fixes = arrayFrom(flatMapIterator(getExportInfos(symbolName, getMeaningFromLocation(symbolToken), cancellationToken, sourceFile, checker, program).entries(), ([_, exportInfos]) => getFixForImport(exportInfos, symbolName, symbolToken.getStart(sourceFile), program, sourceFile, host, preferences))); @@ -468,7 +468,7 @@ namespace ts.codefix { if (defaultExport.flags & SymbolFlags.Alias) { const aliased = checker.getImmediateAliasedSymbol(defaultExport); - return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions); + return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent, "Alias targets of default exports must have a parent"), checker, compilerOptions); } if (defaultExport.escapedName !== InternalSymbolName.Default && @@ -486,7 +486,7 @@ namespace ts.codefix { } } else if (isExportSpecifier(declaration)) { - Debug.assert(declaration.name.text === InternalSymbolName.Default); + Debug.assert(declaration.name.text === InternalSymbolName.Default, "Expected the specifier to be a default export"); return declaration.propertyName && declaration.propertyName.text; } }); @@ -521,13 +521,13 @@ namespace ts.codefix { return [importKind === ImportKind.Default ? Diagnostics.Import_default_0_from_module_1 : Diagnostics.Import_0_from_module_1, symbolName, moduleSpecifier]; } default: - return Debug.assertNever(fix); + return Debug.assertNever(fix, `Unexpected fix kind ${(fix as ImportFix).kind}`); } } function doAddExistingFix(changes: textChanges.ChangeTracker, sourceFile: SourceFile, clause: ImportClause, defaultImport: string | undefined, namedImports: readonly string[]): void { if (defaultImport) { - Debug.assert(!clause.name); + Debug.assert(!clause.name, "Default imports can't have names"); changes.insertNodeAt(sourceFile, clause.getStart(sourceFile), createIdentifier(defaultImport), { suffix: ", " }); } @@ -545,7 +545,7 @@ namespace ts.codefix { changes.replaceNode(sourceFile, clause.namedBindings, namedImports); } else { - changes.insertNodeAfter(sourceFile, Debug.assertDefined(clause.name), namedImports); + changes.insertNodeAfter(sourceFile, Debug.assertDefined(clause.name, "Named import specifiers must have names"), namedImports); } } } diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index f55bdbf458e..02d62cb3b9e 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -211,7 +211,7 @@ namespace ts.codefix { declaration: p, type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType() })); - Debug.assert(containingFunction.parameters.length === parameterInferences.length); + Debug.assert(containingFunction.parameters.length === parameterInferences.length, "Parameter count and inference count should match"); if (isInJSFile(containingFunction)) { annotateJSDocParameters(changes, sourceFile, parameterInferences, program, host); @@ -747,7 +747,7 @@ namespace ts.codefix { for (const i of inferences) { for (const { high, low } of priorities) { if (high(i)) { - Debug.assert(!low(i)); + Debug.assert(!low(i), "Priority can't have both low and high"); toRemove.push(low); } } diff --git a/src/services/refactors/convertExport.ts b/src/services/refactors/convertExport.ts index 7fbe136ada0..66f893dd0a0 100644 --- a/src/services/refactors/convertExport.ts +++ b/src/services/refactors/convertExport.ts @@ -12,8 +12,8 @@ namespace ts.refactor { return [{ name: refactorName, description, actions: [{ name: actionName, description }] }]; }, getEditsForAction(context, actionName): RefactorEditInfo { - Debug.assert(actionName === actionNameDefaultToNamed || actionName === actionNameNamedToDefault); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, Debug.assertDefined(getInfo(context)), t, context.cancellationToken)); + Debug.assert(actionName === actionNameDefaultToNamed || actionName === actionNameNamedToDefault, "Unexpected action name"); + const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, Debug.assertDefined(getInfo(context), "context must have info"), t, context.cancellationToken)); return { edits, renameFilename: undefined, renameLocation: undefined }; }, }); @@ -63,7 +63,7 @@ namespace ts.refactor { } const decl = first(vs.declarationList.declarations); if (!decl.initializer) return undefined; - Debug.assert(!wasDefault); + Debug.assert(!wasDefault, "Can't have a default flag here"); return isIdentifier(decl.name) ? { exportNode: vs, exportName: decl.name, wasDefault, exportingModuleSymbol } : undefined; } default: @@ -78,10 +78,10 @@ namespace ts.refactor { function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, exportName }: Info, changes: textChanges.ChangeTracker, checker: TypeChecker): void { if (wasDefault) { - changes.delete(exportingSourceFile, Debug.assertDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword))); + changes.delete(exportingSourceFile, Debug.assertDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list")); } else { - const exportKeyword = Debug.assertDefined(findModifier(exportNode, SyntaxKind.ExportKeyword)); + const exportKeyword = Debug.assertDefined(findModifier(exportNode, SyntaxKind.ExportKeyword), "Should find an export keyword in modifier list"); switch (exportNode.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: @@ -92,7 +92,7 @@ namespace ts.refactor { // If 'x' isn't used in this file, `export const x = 0;` --> `export default 0;` if (!FindAllReferences.Core.isSymbolReferencedInFile(exportName, checker, exportingSourceFile)) { // We checked in `getInfo` that an initializer exists. - changes.replaceNode(exportingSourceFile, exportNode, createExportDefault(Debug.assertDefined(first(exportNode.declarationList.declarations).initializer))); + changes.replaceNode(exportingSourceFile, exportNode, createExportDefault(Debug.assertDefined(first(exportNode.declarationList.declarations).initializer, "Initializer was previously known to be present"))); break; } // falls through @@ -104,14 +104,14 @@ namespace ts.refactor { changes.insertNodeAfter(exportingSourceFile, exportNode, createExportDefault(createIdentifier(exportName.text))); break; default: - Debug.assertNever(exportNode); + Debug.assertNever(exportNode, `Unexpected exportNode kind ${(exportNode as ExportToConvert).kind}`); } } } function changeImports(program: Program, { wasDefault, exportName, exportingModuleSymbol }: Info, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void { const checker = program.getTypeChecker(); - const exportSymbol = Debug.assertDefined(checker.getSymbolAtLocation(exportName)); + const exportSymbol = Debug.assertDefined(checker.getSymbolAtLocation(exportName), "Export name should resolve to a symbol"); FindAllReferences.Core.eachExportReference(program.getSourceFiles(), checker, cancellationToken, exportSymbol, exportingModuleSymbol, exportName.text, wasDefault, ref => { const importingSourceFile = ref.getSourceFile(); if (wasDefault) { @@ -139,7 +139,7 @@ namespace ts.refactor { } case SyntaxKind.ImportClause: { const clause = parent as ImportClause; - Debug.assert(clause.name === ref); + Debug.assert(clause.name === ref, "Import clause name should match provided ref"); const spec = makeImportSpecifier(exportName, ref.text); const { namedBindings } = clause; if (!namedBindings) { @@ -194,7 +194,7 @@ namespace ts.refactor { break; } default: - Debug.assertNever(parent); + Debug.assertNever(parent, `Unexpected parent kind ${(parent as Node).kind}`); } } diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts index 45eeca579df..f87e90dba4a 100644 --- a/src/services/refactors/convertImport.ts +++ b/src/services/refactors/convertImport.ts @@ -12,8 +12,8 @@ namespace ts.refactor { return [{ name: refactorName, description, actions: [{ name: actionName, description }] }]; }, getEditsForAction(context, actionName): RefactorEditInfo { - Debug.assert(actionName === actionNameNamespaceToNamed || actionName === actionNameNamedToNamespace); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, t, Debug.assertDefined(getImportToConvert(context)))); + Debug.assert(actionName === actionNameNamespaceToNamed || actionName === actionNameNamedToNamespace, "Unexpected action name"); + const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, t, Debug.assertDefined(getImportToConvert(context), "Context must provide an import to convert"))); return { edits, renameFilename: undefined, renameLocation: undefined }; } }); @@ -55,7 +55,7 @@ namespace ts.refactor { if (checker.resolveName(exportName, id, SymbolFlags.All, /*excludeGlobals*/ true)) { conflictingNames.set(exportName, true); } - Debug.assert(parent.expression === id); + Debug.assert(parent.expression === id, "Parent expression should match id"); nodesToReplace.push(parent); } }); diff --git a/src/services/refactors/convertParamsToDestructuredObject.ts b/src/services/refactors/convertParamsToDestructuredObject.ts index 275f14a4a57..6778eeb79c5 100644 --- a/src/services/refactors/convertParamsToDestructuredObject.ts +++ b/src/services/refactors/convertParamsToDestructuredObject.ts @@ -24,7 +24,7 @@ namespace ts.refactor.convertParamsToDestructuredObject { } function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { - Debug.assert(actionName === refactorName); + Debug.assert(actionName === refactorName, "Unexpected action name"); const { file, startPosition, program, cancellationToken, host } = context; const functionDeclaration = getFunctionDeclarationAtPosition(file, startPosition, program.getTypeChecker()); if (!functionDeclaration || !cancellationToken) return undefined; @@ -563,7 +563,7 @@ namespace ts.refactor.convertParamsToDestructuredObject { if (functionDeclaration.name) return [functionDeclaration.name, functionDeclaration.parent.name]; return [functionDeclaration.parent.name]; default: - return Debug.assertNever(functionDeclaration); + return Debug.assertNever(functionDeclaration, `Unexpected function declaration kind ${(functionDeclaration as ValidFunctionDeclaration).kind}`); } } diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 12170d8779b..950bb078e06 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -335,10 +335,10 @@ namespace ts.refactor.extractSymbol { } // We believe it's true because the node is from the (unmodified) tree. - Debug.assert(nodeToCheck.pos <= nodeToCheck.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); + Debug.assert(nodeToCheck.pos <= nodeToCheck.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (1)"); // For understanding how skipTrivia functioned: - Debug.assert(!positionIsSynthesized(nodeToCheck.pos), "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); + Debug.assert(!positionIsSynthesized(nodeToCheck.pos), "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (2)"); if (!isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck))) { return [createDiagnosticForNode(nodeToCheck, Messages.statementOrExpressionExpected)]; @@ -681,7 +681,7 @@ namespace ts.refactor.extractSymbol { case SyntaxKind.SetAccessor: return `'set ${scope.name.getText()}'`; default: - throw Debug.assertNever(scope); + throw Debug.assertNever(scope, `Unexpected scope kind ${(scope as FunctionLikeDeclaration).kind}`); } } function getDescriptionForClassLikeDeclaration(scope: ClassLikeDeclaration): string { @@ -837,8 +837,8 @@ namespace ts.refactor.extractSymbol { // No need to mix declarations and writes. // How could any variables be exposed if there's a return statement? - Debug.assert(!returnValueProperty); - Debug.assert(!(range.facts & RangeFacts.HasReturn)); + Debug.assert(!returnValueProperty, "Expected no returnValueProperty"); + Debug.assert(!(range.facts & RangeFacts.HasReturn), "Expected RangeFacts.HasReturn flag to be unset"); if (exposedVariableDeclarations.length === 1) { // Declaring exactly one variable: let x = newFunction(); @@ -928,7 +928,7 @@ namespace ts.refactor.extractSymbol { if (assignments.length === 1) { // We would only have introduced a return value property if there had been // other assignments to make. - Debug.assert(!returnValueProperty); + Debug.assert(!returnValueProperty, "Shouldn't have returnValueProperty here"); newNodes.push(createStatement(createAssignment(assignments[0].name, call))); @@ -1016,7 +1016,7 @@ namespace ts.refactor.extractSymbol { const changeTracker = textChanges.ChangeTracker.fromContext(context); if (isClassLike(scope)) { - Debug.assert(!isJS); // See CannotExtractToJSClass + Debug.assert(!isJS, "Cannot extract to a JS class"); // See CannotExtractToJSClass const modifiers: Modifier[] = []; modifiers.push(createToken(SyntaxKind.PrivateKeyword)); if (rangeFacts & RangeFacts.InStaticRegion) { @@ -1255,7 +1255,7 @@ namespace ts.refactor.extractSymbol { function getNodeToInsertPropertyBefore(maxPos: number, scope: ClassLikeDeclaration): ClassElement { const members = scope.members; - Debug.assert(members.length > 0); // There must be at least one child, since we extracted from one. + Debug.assert(members.length > 0, "Found no members"); // There must be at least one child, since we extracted from one. let prevMember: ClassElement | undefined; let allProperties = true; @@ -1301,12 +1301,12 @@ namespace ts.refactor.extractSymbol { if (!prevStatement && isCaseClause(curr)) { // We must have been in the expression of the case clause. - Debug.assert(isSwitchStatement(curr.parent.parent)); + Debug.assert(isSwitchStatement(curr.parent.parent), "Grandparent isn't a switch statement"); return curr.parent.parent; } // There must be at least one statement since we started in one. - return Debug.assertDefined(prevStatement); + return Debug.assertDefined(prevStatement, "prevStatement failed to get set"); } Debug.assert(curr !== scope, "Didn't encounter a block-like before encountering scope"); @@ -1476,7 +1476,7 @@ namespace ts.refactor.extractSymbol { // If we didn't get through all the scopes, then there were some that weren't in our // parent chain (impossible at time of writing). A conservative solution would be to // copy allTypeParameterUsages into all remaining scopes. - Debug.assert(i === scopes.length); + Debug.assert(i === scopes.length, "Should have iterated all scopes"); } // If there are any declarations in the extracted block that are used in the same enclosing @@ -1512,7 +1512,7 @@ namespace ts.refactor.extractSymbol { }); // If an expression was extracted, then there shouldn't have been any variable declarations. - Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0); + Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0, "No variable declarations expected if something was extracted"); if (hasWrite && !isReadonlyArray(targetRange.range)) { const diag = createDiagnosticForNode(targetRange.range, Messages.cannotWriteInExpression); diff --git a/src/services/refactors/extractType.ts b/src/services/refactors/extractType.ts index 5feb78d3e90..b77fc72a182 100644 --- a/src/services/refactors/extractType.ts +++ b/src/services/refactors/extractType.ts @@ -19,10 +19,10 @@ namespace ts.refactor { }]; }, getEditsForAction(context, actionName): RefactorEditInfo { - Debug.assert(actionName === extractToTypeAlias || actionName === extractToTypeDef); + Debug.assert(actionName === extractToTypeAlias || actionName === extractToTypeDef, "Unexpected action name"); const { file } = context; - const info = Debug.assertDefined(getRangeToExtract(context)); - Debug.assert(actionName === extractToTypeAlias && !info.isJS || actionName === extractToTypeDef && info.isJS); + const info = Debug.assertDefined(getRangeToExtract(context), "Expected to find a range to extract"); + Debug.assert(actionName === extractToTypeAlias && !info.isJS || actionName === extractToTypeDef && info.isJS, "Invalid actionName/JS combo"); const name = getUniqueName("NewType", file); const edits = textChanges.ChangeTracker.with(context, changes => info.isJS ? @@ -47,7 +47,7 @@ namespace ts.refactor { if (!selection || !isTypeNode(selection)) return undefined; const checker = context.program.getTypeChecker(); - const firstStatement = Debug.assertDefined(isJS ? findAncestor(selection, isStatementAndHasJSDoc) : findAncestor(selection, isStatement)); + const firstStatement = Debug.assertDefined(isJS ? findAncestor(selection, isStatementAndHasJSDoc) : findAncestor(selection, isStatement), "Should find a statement"); const typeParameters = collectTypeParameters(checker, selection, firstStatement, file); if (!typeParameters) return undefined; diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index debd4311aef..b187a0f953b 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -8,7 +8,7 @@ namespace ts.refactor { return [{ name: refactorName, description, actions: [{ name: refactorName, description }] }]; }, getEditsForAction(context, actionName): RefactorEditInfo { - Debug.assert(actionName === refactorName); + Debug.assert(actionName === refactorName, "Wrong refactor invoked"); const statements = Debug.assertDefined(getStatementsToMove(context)); const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, statements, t, context.host, context.preferences)); return { edits, renameFilename: undefined, renameLocation: undefined }; @@ -184,7 +184,7 @@ namespace ts.refactor { case SyntaxKind.VariableDeclaration: return tryCast(node.name, isIdentifier); default: - return Debug.assertNever(node); + return Debug.assertNever(node, `Unexpected node kind ${(node as SupportedImport).kind}`); } } @@ -232,7 +232,7 @@ namespace ts.refactor { case SyntaxKind.VariableDeclaration: return createVariableDeclaration(newNamespaceId, /*type*/ undefined, createRequireCall(newModuleString)); default: - return Debug.assertNever(node); + return Debug.assertNever(node, `Unexpected node kind ${(node as SupportedImport).kind}`); } } @@ -290,7 +290,7 @@ namespace ts.refactor { return makeImportIfNecessary(defaultImport, specifiers, path, quotePreference); } else { - Debug.assert(!defaultImport); // If there's a default export, it should have been an es6 module. + Debug.assert(!defaultImport, "No default import should exist"); // If there's a default export, it should have been an es6 module. const bindingElements = imports.map(i => createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, i)); return bindingElements.length ? makeVariableStatement(createObjectBindingPattern(bindingElements), /*type*/ undefined, createRequireCall(createLiteral(path))) @@ -332,7 +332,7 @@ namespace ts.refactor { deleteUnusedImportsInVariableDeclaration(sourceFile, importDecl, changes, isUnused); break; default: - Debug.assertNever(importDecl); + Debug.assertNever(importDecl, `Unexpected import decl kind ${(importDecl as SupportedImport).kind}`); } } function deleteUnusedImportsInDeclaration(sourceFile: SourceFile, importDecl: ImportDeclaration, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void { @@ -472,7 +472,7 @@ namespace ts.refactor { for (const statement of toMove) { forEachTopLevelDeclaration(statement, decl => { - movedSymbols.add(Debug.assertDefined(isExpressionStatement(decl) ? checker.getSymbolAtLocation(decl.expression.left) : decl.symbol)); + movedSymbols.add(Debug.assertDefined(isExpressionStatement(decl) ? checker.getSymbolAtLocation(decl.expression.left) : decl.symbol, "Need a symbol here")); }); } for (const statement of toMove) { @@ -565,7 +565,7 @@ namespace ts.refactor { return name ? makeVariableStatement(name, i.type, createRequireCall(moduleSpecifier), i.parent.flags) : undefined; } default: - return Debug.assertNever(i); + return Debug.assertNever(i, `Unexpected import kind ${(i as SupportedImport).kind}`); } } function filterNamedBindings(namedBindings: NamedImportBindings, keep: (name: Identifier) => boolean): NamedImportBindings | undefined { @@ -654,7 +654,7 @@ namespace ts.refactor { } function isTopLevelDeclarationStatement(node: Node): node is TopLevelDeclarationStatement { - Debug.assert(isSourceFile(node.parent)); + Debug.assert(isSourceFile(node.parent), "Node parent should be a SourceFile"); return isNonVariableTopLevelDeclaration(node) || isVariableStatement(node); } @@ -703,7 +703,7 @@ namespace ts.refactor { case SyntaxKind.ObjectBindingPattern: return firstDefined(name.elements, em => isOmittedExpression(em) ? undefined : forEachTopLevelDeclarationInBindingName(em.name, cb)); default: - return Debug.assertNever(name); + return Debug.assertNever(name, `Unexpected name kind ${(name as BindingName).kind}`); } } @@ -768,7 +768,7 @@ namespace ts.refactor { case SyntaxKind.ExpressionStatement: return Debug.fail(); // Shouldn't try to add 'export' keyword to `exports.x = ...` default: - return Debug.assertNever(d); + return Debug.assertNever(d, `Unexpected declaration kind ${(d as DeclarationStatement).kind}`); } } function addCommonjsExport(decl: TopLevelDeclarationStatement): readonly Statement[] | undefined { @@ -788,9 +788,9 @@ namespace ts.refactor { case SyntaxKind.ImportEqualsDeclaration: return emptyArray; case SyntaxKind.ExpressionStatement: - return Debug.fail(); // Shouldn't try to add 'export' keyword to `exports.x = ...` + return Debug.fail("Can't export an ExpressionStatement"); // Shouldn't try to add 'export' keyword to `exports.x = ...` default: - return Debug.assertNever(decl); + return Debug.assertNever(decl, `Unexpected decl kind ${(decl as TopLevelDeclarationStatement).kind}`); } } diff --git a/tests/baselines/reference/chainedPrototypeAssignment.errors.txt b/tests/baselines/reference/chainedPrototypeAssignment.errors.txt index a79daa92658..154a66c2a58 100644 --- a/tests/baselines/reference/chainedPrototypeAssignment.errors.txt +++ b/tests/baselines/reference/chainedPrototypeAssignment.errors.txt @@ -19,10 +19,10 @@ tests/cases/conformance/salsa/use.js(6,5): error TS2345: Argument of type '"not declare var exports: any; ==== tests/cases/conformance/salsa/mod.js (0 errors) ==== /// - var A = function() { + var A = function A() { this.a = 1 } - var B = function() { + var B = function B() { this.b = 2 } exports.A = A diff --git a/tests/baselines/reference/chainedPrototypeAssignment.symbols b/tests/baselines/reference/chainedPrototypeAssignment.symbols index 800915e5316..a37ce9f01db 100644 --- a/tests/baselines/reference/chainedPrototypeAssignment.symbols +++ b/tests/baselines/reference/chainedPrototypeAssignment.symbols @@ -37,17 +37,19 @@ declare var exports: any; === tests/cases/conformance/salsa/mod.js === /// -var A = function() { +var A = function A() { >A : Symbol(A, Decl(mod.js, 1, 3), Decl(mod.js, 8, 13)) +>A : Symbol(A, Decl(mod.js, 1, 7)) this.a = 1 ->a : Symbol(A.a, Decl(mod.js, 1, 20)) +>a : Symbol(A.a, Decl(mod.js, 1, 22)) } -var B = function() { +var B = function B() { >B : Symbol(B, Decl(mod.js, 4, 3), Decl(mod.js, 9, 13)) +>B : Symbol(B, Decl(mod.js, 4, 7)) this.b = 2 ->b : Symbol(B.b, Decl(mod.js, 4, 20)) +>b : Symbol(B.b, Decl(mod.js, 4, 22)) } exports.A = A >exports.A : Symbol(A, Decl(mod.js, 6, 1)) diff --git a/tests/baselines/reference/chainedPrototypeAssignment.types b/tests/baselines/reference/chainedPrototypeAssignment.types index 6e877361ae6..0e86f9e4049 100644 --- a/tests/baselines/reference/chainedPrototypeAssignment.types +++ b/tests/baselines/reference/chainedPrototypeAssignment.types @@ -44,9 +44,10 @@ declare var exports: any; === tests/cases/conformance/salsa/mod.js === /// -var A = function() { +var A = function A() { +>A : typeof A +>function A() { this.a = 1} : typeof A >A : typeof A ->function() { this.a = 1} : typeof A this.a = 1 >this.a = 1 : 1 @@ -55,9 +56,10 @@ var A = function() { >a : any >1 : 1 } -var B = function() { +var B = function B() { +>B : typeof B +>function B() { this.b = 2} : typeof B >B : typeof B ->function() { this.b = 2} : typeof B this.b = 2 >this.b = 2 : 2 diff --git a/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.errors.txt b/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.errors.txt new file mode 100644 index 00000000000..602294ea5ff --- /dev/null +++ b/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/salsa/other.js(5,5): error TS2339: Property 'wat' does not exist on type 'One'. +tests/cases/conformance/salsa/other.js(10,5): error TS2339: Property 'wat' does not exist on type 'Two'. + + +==== tests/cases/conformance/salsa/prototypePropertyAssignmentMergeAcrossFiles2.js (0 errors) ==== + var Ns = {} + Ns.One = function() {}; + Ns.Two = function() {}; + + Ns.One.prototype = { + ok() {}, + }; + Ns.Two.prototype = { + } + +==== tests/cases/conformance/salsa/other.js (2 errors) ==== + /** + * @type {Ns.One} + */ + var one; + one.wat; + ~~~ +!!! error TS2339: Property 'wat' does not exist on type 'One'. + /** + * @type {Ns.Two} + */ + var two; + two.wat; + ~~~ +!!! error TS2339: Property 'wat' does not exist on type 'Two'. + \ No newline at end of file diff --git a/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.symbols b/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.symbols new file mode 100644 index 00000000000..6646bac5ee9 --- /dev/null +++ b/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.symbols @@ -0,0 +1,52 @@ +=== tests/cases/conformance/salsa/prototypePropertyAssignmentMergeAcrossFiles2.js === +var Ns = {} +>Ns : Symbol(Ns, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 3), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 2, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 6, 2)) + +Ns.One = function() {}; +>Ns.One : Symbol(Ns.One, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 4, 3)) +>Ns : Symbol(Ns, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 3), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 2, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 6, 2)) +>One : Symbol(Ns.One, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 4, 3)) + +Ns.Two = function() {}; +>Ns.Two : Symbol(Ns.Two, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 7, 3)) +>Ns : Symbol(Ns, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 3), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 2, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 6, 2)) +>Two : Symbol(Ns.Two, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 7, 3)) + +Ns.One.prototype = { +>Ns.One.prototype : Symbol(Ns.One.prototype, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 2, 23)) +>Ns.One : Symbol(Ns.One, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 4, 3)) +>Ns : Symbol(Ns, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 3), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 2, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 6, 2)) +>One : Symbol(Ns.One, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 4, 3)) +>prototype : Symbol(Ns.One.prototype, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 2, 23)) + + ok() {}, +>ok : Symbol(ok, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 4, 20)) + +}; +Ns.Two.prototype = { +>Ns.Two.prototype : Symbol(Ns.Two.prototype, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 6, 2)) +>Ns.Two : Symbol(Ns.Two, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 7, 3)) +>Ns : Symbol(Ns, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 3), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 0, 11), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 2, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 6, 2)) +>Two : Symbol(Ns.Two, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 1, 23), Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 7, 3)) +>prototype : Symbol(Ns.Two.prototype, Decl(prototypePropertyAssignmentMergeAcrossFiles2.js, 6, 2)) +} + +=== tests/cases/conformance/salsa/other.js === +/** + * @type {Ns.One} + */ +var one; +>one : Symbol(one, Decl(other.js, 3, 3)) + +one.wat; +>one : Symbol(one, Decl(other.js, 3, 3)) + +/** + * @type {Ns.Two} + */ +var two; +>two : Symbol(two, Decl(other.js, 8, 3)) + +two.wat; +>two : Symbol(two, Decl(other.js, 8, 3)) + diff --git a/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.types b/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.types new file mode 100644 index 00000000000..691eefb2f1a --- /dev/null +++ b/tests/baselines/reference/prototypePropertyAssignmentMergeAcrossFiles2.types @@ -0,0 +1,65 @@ +=== tests/cases/conformance/salsa/prototypePropertyAssignmentMergeAcrossFiles2.js === +var Ns = {} +>Ns : typeof Ns +>{} : {} + +Ns.One = function() {}; +>Ns.One = function() {} : typeof One +>Ns.One : typeof One +>Ns : typeof Ns +>One : typeof One +>function() {} : typeof One + +Ns.Two = function() {}; +>Ns.Two = function() {} : typeof Two +>Ns.Two : typeof Two +>Ns : typeof Ns +>Two : typeof Two +>function() {} : typeof Two + +Ns.One.prototype = { +>Ns.One.prototype = { ok() {},} : { ok(): void; } +>Ns.One.prototype : { ok(): void; } +>Ns.One : typeof One +>Ns : typeof Ns +>One : typeof One +>prototype : { ok(): void; } +>{ ok() {},} : { ok(): void; } + + ok() {}, +>ok : () => void + +}; +Ns.Two.prototype = { +>Ns.Two.prototype = {} : {} +>Ns.Two.prototype : {} +>Ns.Two : typeof Two +>Ns : typeof Ns +>Two : typeof Two +>prototype : {} +>{} : {} +} + +=== tests/cases/conformance/salsa/other.js === +/** + * @type {Ns.One} + */ +var one; +>one : One + +one.wat; +>one.wat : any +>one : One +>wat : any + +/** + * @type {Ns.Two} + */ +var two; +>two : Two + +two.wat; +>two.wat : any +>two : Two +>wat : any + diff --git a/tests/cases/conformance/salsa/chainedPrototypeAssignment.ts b/tests/cases/conformance/salsa/chainedPrototypeAssignment.ts index ffac0eef1fc..df6686dda9d 100644 --- a/tests/cases/conformance/salsa/chainedPrototypeAssignment.ts +++ b/tests/cases/conformance/salsa/chainedPrototypeAssignment.ts @@ -7,10 +7,10 @@ declare function require(name: string): any; declare var exports: any; // @Filename: mod.js /// -var A = function() { +var A = function A() { this.a = 1 } -var B = function() { +var B = function B() { this.b = 2 } exports.A = A diff --git a/tests/cases/conformance/salsa/prototypePropertyAssignmentMergeAcrossFiles2.ts b/tests/cases/conformance/salsa/prototypePropertyAssignmentMergeAcrossFiles2.ts new file mode 100644 index 00000000000..6d1018d7afc --- /dev/null +++ b/tests/cases/conformance/salsa/prototypePropertyAssignmentMergeAcrossFiles2.ts @@ -0,0 +1,25 @@ +// @Filename: prototypePropertyAssignmentMergeAcrossFiles2.js +// @allowJs: true +// @checkJs: true +// @noEmit: true +var Ns = {} +Ns.One = function() {}; +Ns.Two = function() {}; + +Ns.One.prototype = { + ok() {}, +}; +Ns.Two.prototype = { +} + +// @Filename: other.js +/** + * @type {Ns.One} + */ +var one; +one.wat; +/** + * @type {Ns.Two} + */ +var two; +two.wat;