diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 27ec079f614ab..cfa409e878c82 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -46,7 +46,6 @@ import { DeleteExpression, DestructuringAssignment, DiagnosticArguments, - DiagnosticCategory, DiagnosticMessage, DiagnosticRelatedInformation, Diagnostics, @@ -87,7 +86,6 @@ import { getAssignmentDeclarationKind, getAssignmentDeclarationPropertyAccessKind, getCombinedModifierFlags, - getCombinedNodeFlags, getContainingClass, getEffectiveContainerForJSDocTemplateTag, getElementOrPropertyAccessName, @@ -106,7 +104,6 @@ import { getNameOfDeclaration, getNameOrArgument, getNodeId, - getRangesWhere, getRightMostAssignedExpression, getSourceFileOfNode, getSourceTextOfNodeFromSourceFile, @@ -115,10 +112,8 @@ import { getSymbolNameForPrivateIdentifier, getTextOfIdentifierOrLiteral, getThisContainer, - getTokenPosOfNode, HasContainerFlags, hasDynamicName, - HasFlowNode, hasJSDocNodes, HasLocals, hasSyntacticModifier, @@ -164,7 +159,6 @@ import { isExternalModule, isExternalOrCommonJsModule, isForInOrOfStatement, - isFunctionDeclaration, isFunctionLike, isFunctionLikeDeclaration, isFunctionLikeOrClassStaticBlockDeclaration, @@ -204,6 +198,7 @@ import { isParenthesizedExpression, isPartOfParameterDeclaration, isPartOfTypeQuery, + isPotentiallyExecutableNode, isPrefixUnaryExpression, isPrivateIdentifier, isPrologueDirective, @@ -217,8 +212,6 @@ import { isSignedNumericLiteral, isSourceFile, isSpecialPropertyDeclaration, - isStatement, - isStatementButNotDeclaration, isStatic, isString, isStringLiteralLike, @@ -286,10 +279,8 @@ import { setParentRecursive, setValueDeclaration, ShorthandPropertyAssignment, - shouldPreserveConstEnums, SignatureDeclaration, skipParentheses, - sliceAfter, some, SourceFile, SpreadElement, @@ -302,7 +293,6 @@ import { symbolName, SymbolTable, SyntaxKind, - TextRange, ThisExpression, ThrowStatement, tokenToString, @@ -315,8 +305,6 @@ import { TypeOfExpression, TypeParameterDeclaration, unescapeLeadingUnderscores, - unreachableCodeIsError, - unusedLabelIsError, VariableDeclaration, WhileStatement, WithStatement, @@ -565,7 +553,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { var classifiableNames: Set<__String>; var unreachableFlow = createFlowNode(FlowFlags.Unreachable, /*node*/ undefined, /*antecedent*/ undefined); - var reportedUnreachableFlow = createFlowNode(FlowFlags.Unreachable, /*node*/ undefined, /*antecedent*/ undefined); var bindBinaryExpressionFlow = createBindBinaryExpressionFlow(); /* eslint-enable no-var */ @@ -592,7 +579,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // Attach debugging information if necessary Debug.attachFlowNodeDebugInfo(unreachableFlow); - Debug.attachFlowNodeDebugInfo(reportedUnreachableFlow); if (!file.locals) { tracing?.push(tracing.Phase.Bind, "bindSourceFile", { path: file.path }, /*separateBeginAndEnd*/ true); @@ -1104,18 +1090,24 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // Most nodes aren't valid in an assignment pattern, so we clear the value here // and set it before we descend into nodes that could actually be part of an assignment pattern. inAssignmentPattern = false; - if (checkUnreachable(node)) { - if (canHaveFlowNode(node) && node.flowNode) { + + if (currentFlow === unreachableFlow) { + if (canHaveFlowNode(node)) { node.flowNode = undefined; } + if (isPotentiallyExecutableNode(node)) { + (node as Mutable).flags |= NodeFlags.Unreachable; + } bindEachChild(node); bindJSDoc(node); inAssignmentPattern = saveInAssignmentPattern; return; } - if (node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement && (!options.allowUnreachableCode || node.kind === SyntaxKind.ReturnStatement)) { - (node as HasFlowNode).flowNode = currentFlow; + + if (SyntaxKind.FirstStatement <= node.kind && node.kind <= SyntaxKind.LastStatement && canHaveFlowNode(node)) { + node.flowNode = currentFlow; } + switch (node.kind) { case SyntaxKind.WhileStatement: bindWhileStatement(node as WhileStatement); @@ -1793,8 +1785,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { }; bind(node.label); bind(node.statement); - if (!activeLabelList.referenced && !options.allowUnusedLabels) { - errorOrSuggestionOnNode(unusedLabelIsError(options), node.label, Diagnostics.Unused_label); + if (!activeLabelList.referenced) { + (node.label as Mutable).flags |= NodeFlags.Unreachable; } activeLabelList = activeLabelList.next; addAntecedent(postStatementLabel, currentFlow); @@ -2743,24 +2735,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, ...args)); } - function errorOrSuggestionOnNode(isError: boolean, node: Node, message: DiagnosticMessage): void { - errorOrSuggestionOnRange(isError, node, node, message); - } - - function errorOrSuggestionOnRange(isError: boolean, startNode: Node, endNode: Node, message: DiagnosticMessage): void { - addErrorOrSuggestionDiagnostic(isError, { pos: getTokenPosOfNode(startNode, file), end: endNode.end }, message); - } - - function addErrorOrSuggestionDiagnostic(isError: boolean, range: TextRange, message: DiagnosticMessage): void { - const diag = createFileDiagnostic(file, range.pos, range.end - range.pos, message); - if (isError) { - file.bindDiagnostics.push(diag); - } - else { - file.bindSuggestionDiagnostics = append(file.bindSuggestionDiagnostics, { ...diag, category: DiagnosticCategory.Suggestion }); - } - } - function bind(node: Node | undefined): void { if (!node) { return; @@ -3793,93 +3767,6 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); } } - - // reachability checks - - function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { - const instanceState = getModuleInstanceState(node); - return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && shouldPreserveConstEnums(options)); - } - - function checkUnreachable(node: Node): boolean { - if (!(currentFlow.flags & FlowFlags.Unreachable)) { - return false; - } - if (currentFlow === unreachableFlow) { - const reportError = - // report error on all statements except empty ones - (isStatementButNotDeclaration(node) && node.kind !== SyntaxKind.EmptyStatement) || - // report error on class declarations - node.kind === SyntaxKind.ClassDeclaration || - // report errors on enums with preserved emit - isEnumDeclarationWithPreservedEmit(node, options) || - // report error on instantiated modules - (node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(node as ModuleDeclaration)); - - if (reportError) { - currentFlow = reportedUnreachableFlow; - - if (!options.allowUnreachableCode) { - // unreachable code is reported if - // - user has explicitly asked about it AND - // - statement is in not ambient context (statements in ambient context is already an error - // so we should not report extras) AND - // - node is not variable statement OR - // - node is block scoped variable statement OR - // - node is not block scoped variable statement and at least one variable declaration has initializer - // Rationale: we don't want to report errors on non-initialized var's since they are hoisted - // On the other side we do want to report errors on non-initialized 'lets' because of TDZ - const isError = unreachableCodeIsError(options) && - !(node.flags & NodeFlags.Ambient) && - ( - !isVariableStatement(node) || - !!(getCombinedNodeFlags(node.declarationList) & NodeFlags.BlockScoped) || - node.declarationList.declarations.some(d => !!d.initializer) - ); - - eachUnreachableRange(node, options, (start, end) => errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected)); - } - } - } - return true; - } -} - -function isEnumDeclarationWithPreservedEmit(node: Node, options: CompilerOptions): boolean { - return node.kind === SyntaxKind.EnumDeclaration && (!isEnumConst(node as EnumDeclaration) || shouldPreserveConstEnums(options)); -} - -function eachUnreachableRange(node: Node, options: CompilerOptions, cb: (start: Node, last: Node) => void): void { - if (isStatement(node) && isExecutableStatement(node) && isBlock(node.parent)) { - const { statements } = node.parent; - const slice = sliceAfter(statements, node); - getRangesWhere(slice, isExecutableStatement, (start, afterEnd) => cb(slice[start], slice[afterEnd - 1])); - } - else { - cb(node, node); - } - - // As opposed to a pure declaration like an `interface` - function isExecutableStatement(s: Statement): boolean { - // Don't remove statements that can validly be used before they appear. - return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && - // `var x;` may declare a variable used above - !(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.BlockScoped)) && s.declarationList.declarations.some(d => !d.initializer)); - } - - function isPurelyTypeDeclaration(s: Statement): boolean { - switch (s.kind) { - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.TypeAliasDeclaration: - return true; - case SyntaxKind.ModuleDeclaration: - return getModuleInstanceState(s as ModuleDeclaration) !== ModuleInstanceState.Instantiated; - case SyntaxKind.EnumDeclaration: - return !isEnumDeclarationWithPreservedEmit(s, options); - default: - return false; - } - } } /** @internal */ diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fa2a56e2fdfa6..ba5765c0826a3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -62,6 +62,7 @@ import { canHaveLocals, canHaveModifiers, canHaveModuleSpecifier, + canHaveStatements, canHaveSymbol, canIncludeBindAndCheckDiagnostics, canUsePropertyAccess, @@ -708,6 +709,7 @@ import { isPartOfTypeOnlyImportOrExportDeclaration, isPartOfTypeQuery, isPlainJsFile, + isPotentiallyExecutableNode, isPrefixUnaryExpression, isPrivateIdentifier, isPrivateIdentifierClassElementDeclaration, @@ -1512,6 +1514,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var currentNode: Node | undefined; var varianceTypeParameter: TypeParameter | undefined; var isInferencePartiallyBlocked = false; + var withinUnreachableCode = false; + var reportedUnreachableNodes: Set | undefined; var emptySymbols = createSymbolTable(); var arrayVariances = [VarianceFlags.Covariant]; @@ -46603,6 +46607,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } + if (node.label.flags & NodeFlags.Unreachable && compilerOptions.allowUnusedLabels !== true) { + errorOrSuggestion(compilerOptions.allowUnusedLabels === false, node.label, Diagnostics.Unused_label); + } + // ensure that label is unique checkSourceElement(node.statement); } @@ -48967,10 +48975,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkSourceElement(node: Node | undefined): void { if (node) { const saveCurrentNode = currentNode; + const saveWithinUnreachableCode = withinUnreachableCode; currentNode = node; instantiationCount = 0; checkSourceElementWorker(node); currentNode = saveCurrentNode; + withinUnreachableCode = saveWithinUnreachableCode; } } @@ -49003,8 +49013,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { cancellationToken.throwIfCancellationRequested(); } } - if (kind >= SyntaxKind.FirstStatement && kind <= SyntaxKind.LastStatement && canHaveFlowNode(node) && node.flowNode && !isReachableFlowNode(node.flowNode)) { - errorOrSuggestion(compilerOptions.allowUnreachableCode === false, node, Diagnostics.Unreachable_code_detected); + + if (compilerOptions.allowUnreachableCode !== true && !withinUnreachableCode) { + if (checkSourceElementUnreachable(node)) { + withinUnreachableCode = true; + } } // If editing this, keep `isSourceElement` in utilities up to date. @@ -49185,6 +49198,86 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function checkSourceElementUnreachable(node: Node): boolean { + if (!isPotentiallyExecutableNode(node)) { + return false; + } + + if (reportedUnreachableNodes?.has(node)) { + return true; + } + + if (!isSourceElementUnreachable(node)) { + return false; + } + + (reportedUnreachableNodes ??= new Set()).add(node); + + const sourceFile = getSourceFileOfNode(node); + + let start = node.pos; + let end = node.end; + + const parent = node.parent; + if (canHaveStatements(parent)) { + const statements = parent.statements; + const offset = statements.indexOf(node as Statement); + if (offset >= 0) { + // Scan backwards to find the first unreachable unreported node; + // this may happen when producing region diagnostics where not all nodes + // will have been visited. + let first = offset; + for (let i = offset - 1; i >= 0; i--) { + const prevNode = statements[i]; + if (!isPotentiallyExecutableNode(prevNode) || reportedUnreachableNodes.has(prevNode) || !isSourceElementUnreachable(prevNode)) { + break; + } + first = i; + reportedUnreachableNodes.add(prevNode); + } + + let last = offset; + for (let i = offset + 1; i < statements.length; i++) { + const nextNode = statements[i]; + if (!isPotentiallyExecutableNode(nextNode) || !isSourceElementUnreachable(nextNode)) { + break; + } + last = i; + reportedUnreachableNodes.add(nextNode); + } + + start = statements[first].pos; + end = statements[last].end; + } + } + + start = skipTrivia(sourceFile.text, start); + addErrorOrSuggestion(compilerOptions.allowUnreachableCode === false, createFileDiagnostic(sourceFile, start, end - start, Diagnostics.Unreachable_code_detected)); + + return true; + } + + function isSourceElementUnreachable(node: Node): boolean { + // Precondition: isPotentiallyExecutableNode is true + if (node.flags & NodeFlags.Unreachable) { + // The binder has determined that this code is unreachable. + // Ignore const enums unless preserveConstEnums is set. + switch (node.kind) { + case SyntaxKind.EnumDeclaration: + return !isEnumConst(node as EnumDeclaration) || shouldPreserveConstEnums(compilerOptions); + case SyntaxKind.ModuleDeclaration: + return isInstantiatedModule(node as ModuleDeclaration, shouldPreserveConstEnums(compilerOptions)); + default: + return true; + } + } + else if (canHaveFlowNode(node) && node.flowNode) { + // For code the binder doesn't know is unreachable, use control flow / types. + return !isReachableFlowNode(node.flowNode); + } + return false; + } + function checkJSDocCommentWorker(node: string | readonly JSDocComment[] | undefined) { if (isArray(node)) { forEach(node, tag => { @@ -49383,6 +49476,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { performance.mark(afterMark); performance.measure("Check", beforeMark, afterMark); tracing?.pop(); + reportedUnreachableNodes = undefined; } function unusedIsError(kind: UnusedKind, isAmbient: boolean): boolean { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 626bcecf9d34a..617ec4d8bda75 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -823,6 +823,7 @@ export const enum NodeFlags { JsonFile = 1 << 27, // If node was parsed in a Json /** @internal */ TypeCached = 1 << 28, // If a type was cached for node at any point /** @internal */ Deprecated = 1 << 29, // If has '@deprecated' JSDoc tag + /** @internal */ Unreachable = 1 << 30, // If node is unreachable according to the binder BlockScoped = Let | Const | Using, Constant = Const | Using, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9805b7ae9b1e4..cdf898ca8c3fc 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -261,7 +261,9 @@ import { isBinaryExpression, isBindingElement, isBindingPattern, + isBlock, isCallExpression, + isCaseClause, isClassDeclaration, isClassElement, isClassExpression, @@ -274,6 +276,7 @@ import { isDeclaration, isDeclarationFileName, isDecorator, + isDefaultClause, isElementAccessExpression, isEnumDeclaration, isEnumMember, @@ -332,6 +335,7 @@ import { isMethodDeclaration, isMethodOrAccessor, isModifierLike, + isModuleBlock, isModuleDeclaration, isModuleOrEnumDeclaration, isNamedDeclaration, @@ -9273,16 +9277,6 @@ export function hasJsonModuleEmitEnabled(options: CompilerOptions): boolean { return true; } -/** @internal */ -export function unreachableCodeIsError(options: CompilerOptions): boolean { - return options.allowUnreachableCode === false; -} - -/** @internal */ -export function unusedLabelIsError(options: CompilerOptions): boolean { - return options.allowUnusedLabels === false; -} - /** @internal */ export function moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution: ModuleResolutionKind): boolean { return moduleResolution >= ModuleResolutionKind.Node16 && moduleResolution <= ModuleResolutionKind.NodeNext @@ -12372,3 +12366,22 @@ function addEmitFlagsRecursively(node: Node, flag: EmitFlags, getChild: (n: Node function getFirstChild(node: Node): Node | undefined { return forEachChild(node, child => child); } + +/** @internal */ +export function canHaveStatements(node: Node): node is Block | ModuleBlock | SourceFile | CaseClause | DefaultClause { + return isBlock(node) || isModuleBlock(node) || isSourceFile(node) || isCaseClause(node) || isDefaultClause(node); +} + +/** @internal */ +export function isPotentiallyExecutableNode(node: Node): boolean { + if (SyntaxKind.FirstStatement <= node.kind && node.kind <= SyntaxKind.LastStatement) { + if (isVariableStatement(node)) { + if (getCombinedNodeFlags(node.declarationList) & NodeFlags.BlockScoped) { + return true; + } + return some(node.declarationList.declarations, d => d.initializer !== undefined); + } + return true; + } + return isClassDeclaration(node) || isEnumDeclaration(node) || isModuleDeclaration(node); +} diff --git a/tests/baselines/reference/neverReturningFunctions1.errors.txt b/tests/baselines/reference/neverReturningFunctions1.errors.txt index 8a7a8837147b9..a15d15e17dbba 100644 --- a/tests/baselines/reference/neverReturningFunctions1.errors.txt +++ b/tests/baselines/reference/neverReturningFunctions1.errors.txt @@ -13,7 +13,6 @@ neverReturningFunctions1.ts(101,13): error TS7027: Unreachable code detected. neverReturningFunctions1.ts(103,9): error TS7027: Unreachable code detected. neverReturningFunctions1.ts(105,5): error TS7027: Unreachable code detected. neverReturningFunctions1.ts(111,9): error TS7027: Unreachable code detected. -neverReturningFunctions1.ts(112,9): error TS7027: Unreachable code detected. neverReturningFunctions1.ts(122,9): error TS7027: Unreachable code detected. neverReturningFunctions1.ts(127,9): error TS7027: Unreachable code detected. neverReturningFunctions1.ts(129,5): error TS7027: Unreachable code detected. @@ -23,7 +22,7 @@ neverReturningFunctions1.ts(148,9): error TS7027: Unreachable code detected. neverReturningFunctions1.ts(153,5): error TS7027: Unreachable code detected. -==== neverReturningFunctions1.ts (23 errors) ==== +==== neverReturningFunctions1.ts (22 errors) ==== function fail(message?: string): never { throw new Error(message); } @@ -163,10 +162,9 @@ neverReturningFunctions1.ts(153,5): error TS7027: Unreachable code detected. if (typeof x.a === "string") { fail(); x; // Unreachable - ~~ -!!! error TS7027: Unreachable code detected. + ~~~~~~~~~~~~~~~~~~~~ x.a; // Unreachable - ~~~~ + ~~~~~~~~~~~~ !!! error TS7027: Unreachable code detected. } x; // { a: string | number } diff --git a/tests/baselines/reference/reachabilityChecks1.errors.txt b/tests/baselines/reference/reachabilityChecks1.errors.txt index 8220dd8a921b3..ff7ff2d4a07f5 100644 --- a/tests/baselines/reference/reachabilityChecks1.errors.txt +++ b/tests/baselines/reference/reachabilityChecks1.errors.txt @@ -1,58 +1,77 @@ reachabilityChecks1.ts(2,1): error TS7027: Unreachable code detected. -reachabilityChecks1.ts(6,5): error TS7027: Unreachable code detected. -reachabilityChecks1.ts(18,5): error TS7027: Unreachable code detected. -reachabilityChecks1.ts(30,5): error TS7027: Unreachable code detected. reachabilityChecks1.ts(47,5): error TS7027: Unreachable code detected. +reachabilityChecks1.ts(51,1): error TS7027: Unreachable code detected. reachabilityChecks1.ts(60,5): error TS7027: Unreachable code detected. reachabilityChecks1.ts(69,5): error TS7027: Unreachable code detected. -==== reachabilityChecks1.ts (7 errors) ==== +==== reachabilityChecks1.ts (5 errors) ==== while (true); var x = 1; ~~~~~~~~~~ -!!! error TS7027: Unreachable code detected. + namespace A { + ~~~~~~~~~~~~~ while (true); + ~~~~~~~~~~~~~~~~~ let x; - ~~~~~~ -!!! error TS7027: Unreachable code detected. + ~~~~~~~~~~ } + ~ + namespace A1 { + ~~~~~~~~~~~~~~ do {} while(true); + ~~~~~~~~~~~~~~~~~~~~~~ namespace A { + ~~~~~~~~~~~~~~~~~ interface F {} + ~~~~~~~~~~~~~~~~~~~~~~ } + ~~~~~ } + ~ + namespace A2 { + ~~~~~~~~~~~~~~ while (true); + ~~~~~~~~~~~~~~~~~ namespace A { - ~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~ var x = 1; ~~~~~~~~~~~~~~~~~~ } ~~~~~ -!!! error TS7027: Unreachable code detected. } + ~ + namespace A3 { + ~~~~~~~~~~~~~~ while (true); + ~~~~~~~~~~~~~~~~~ type T = string; + ~~~~~~~~~~~~~~~~~~~~ } + ~ + namespace A4 { + ~~~~~~~~~~~~~~ while (true); + ~~~~~~~~~~~~~~~~~ namespace A { - ~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~ const enum E { X } ~~~~~~~~~~~~~~~~~~~~~~~~~~ } ~~~~~ -!!! error TS7027: Unreachable code detected. } + ~ +!!! error TS7027: Unreachable code detected. function f1(x) { if (x) { @@ -74,10 +93,16 @@ reachabilityChecks1.ts(69,5): error TS7027: Unreachable code detected. } namespace B { + ~~~~~~~~~~~~~ for (; ;); + ~~~~~~~~~~~~~~ namespace C { + ~~~~~~~~~~~~~~~~~ } + ~~~~~ } + ~ +!!! error TS7027: Unreachable code detected. function f3() { do { diff --git a/tests/baselines/reference/reachabilityChecks10.errors.txt b/tests/baselines/reference/reachabilityChecks10.errors.txt new file mode 100644 index 0000000000000..2b26eae20f99e --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks10.errors.txt @@ -0,0 +1,11 @@ +reachabilityChecks10.ts(2,1): error TS7027: Unreachable code detected. + + +==== reachabilityChecks10.ts (1 errors) ==== + throw new Error("") + console.log("1") + ~~~~~~~~~~~~~~~~ + console.log("2") + ~~~~~~~~~~~~~~~~ +!!! error TS7027: Unreachable code detected. + \ No newline at end of file diff --git a/tests/baselines/reference/reachabilityChecks10.symbols b/tests/baselines/reference/reachabilityChecks10.symbols new file mode 100644 index 0000000000000..6ecc554153996 --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks10.symbols @@ -0,0 +1,16 @@ +//// [tests/cases/compiler/reachabilityChecks10.ts] //// + +=== reachabilityChecks10.ts === +throw new Error("") +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +console.log("1") +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + +console.log("2") +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + diff --git a/tests/baselines/reference/reachabilityChecks10.types b/tests/baselines/reference/reachabilityChecks10.types new file mode 100644 index 0000000000000..bfe7b1bfefe8d --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks10.types @@ -0,0 +1,35 @@ +//// [tests/cases/compiler/reachabilityChecks10.ts] //// + +=== reachabilityChecks10.ts === +throw new Error("") +>new Error("") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"" : "" +> : ^^ + +console.log("1") +>console.log("1") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"1" : "1" +> : ^^^ + +console.log("2") +>console.log("2") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"2" : "2" +> : ^^^ + diff --git a/tests/baselines/reference/reachabilityChecks11.errors.txt b/tests/baselines/reference/reachabilityChecks11.errors.txt new file mode 100644 index 0000000000000..b4497ee46432a --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks11.errors.txt @@ -0,0 +1,104 @@ +reachabilityChecks11.ts(6,5): error TS7027: Unreachable code detected. +reachabilityChecks11.ts(18,5): error TS7027: Unreachable code detected. +reachabilityChecks11.ts(30,5): error TS7027: Unreachable code detected. +reachabilityChecks11.ts(47,5): error TS7027: Unreachable code detected. +reachabilityChecks11.ts(60,5): error TS7027: Unreachable code detected. +reachabilityChecks11.ts(69,5): error TS7027: Unreachable code detected. + + +==== reachabilityChecks11.ts (6 errors) ==== + // while (true); + var x = 1; + + module A { + while (true); + let x; + ~~~~~~ +!!! error TS7027: Unreachable code detected. + } + + module A1 { + do {} while(true); + module A { + interface F {} + } + } + + module A2 { + while (true); + module A { + ~~~~~~~~~~ + var x = 1; + ~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! error TS7027: Unreachable code detected. + } + + module A3 { + while (true); + type T = string; + } + + module A4 { + while (true); + module A { + ~~~~~~~~~~ + const enum E { X } + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! error TS7027: Unreachable code detected. + } + + function f1(x) { + if (x) { + return; + } + else { + throw new Error("123"); + } + var x; + } + + function f2() { + return; + class A { + ~~~~~~~~~ + } + ~~~~~ +!!! error TS7027: Unreachable code detected. + } + + module B { + for (; ;); + module C { + } + } + + function f3() { + do { + } while (true); + enum E { + ~~~~~~~~ + X = 1 + ~~~~~~~~~~~~~ + } + ~~~~~ +!!! error TS7027: Unreachable code detected. + } + + function f4() { + if (true) { + throw new Error(); + } + const enum E { + ~~~~~~~~~~~~~~ + X = 1 + ~~~~~~~~~~~~~ + } + ~~~~~ +!!! error TS7027: Unreachable code detected. + } + + \ No newline at end of file diff --git a/tests/baselines/reference/reachabilityChecks11.js b/tests/baselines/reference/reachabilityChecks11.js new file mode 100644 index 0000000000000..d115e58e816cb --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks11.js @@ -0,0 +1,156 @@ +//// [tests/cases/compiler/reachabilityChecks11.ts] //// + +//// [reachabilityChecks11.ts] +// while (true); +var x = 1; + +module A { + while (true); + let x; +} + +module A1 { + do {} while(true); + module A { + interface F {} + } +} + +module A2 { + while (true); + module A { + var x = 1; + } +} + +module A3 { + while (true); + type T = string; +} + +module A4 { + while (true); + module A { + const enum E { X } + } +} + +function f1(x) { + if (x) { + return; + } + else { + throw new Error("123"); + } + var x; +} + +function f2() { + return; + class A { + } +} + +module B { + for (; ;); + module C { + } +} + +function f3() { + do { + } while (true); + enum E { + X = 1 + } +} + +function f4() { + if (true) { + throw new Error(); + } + const enum E { + X = 1 + } +} + + + +//// [reachabilityChecks11.js] +// while (true); +var x = 1; +var A; +(function (A) { + while (true) + ; + var x; +})(A || (A = {})); +var A1; +(function (A1) { + do { } while (true); +})(A1 || (A1 = {})); +var A2; +(function (A2) { + while (true) + ; + var A; + (function (A) { + var x = 1; + })(A || (A = {})); +})(A2 || (A2 = {})); +var A3; +(function (A3) { + while (true) + ; +})(A3 || (A3 = {})); +var A4; +(function (A4) { + while (true) + ; + var A; + (function (A) { + var E; + (function (E) { + E[E["X"] = 0] = "X"; + })(E || (E = {})); + })(A || (A = {})); +})(A4 || (A4 = {})); +function f1(x) { + if (x) { + return; + } + else { + throw new Error("123"); + } + var x; +} +function f2() { + return; + var A = /** @class */ (function () { + function A() { + } + return A; + }()); +} +var B; +(function (B) { + for (;;) + ; +})(B || (B = {})); +function f3() { + do { + } while (true); + var E; + (function (E) { + E[E["X"] = 1] = "X"; + })(E || (E = {})); +} +function f4() { + if (true) { + throw new Error(); + } + var E; + (function (E) { + E[E["X"] = 1] = "X"; + })(E || (E = {})); +} diff --git a/tests/baselines/reference/reachabilityChecks11.symbols b/tests/baselines/reference/reachabilityChecks11.symbols new file mode 100644 index 0000000000000..450ccad803ff5 --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks11.symbols @@ -0,0 +1,124 @@ +//// [tests/cases/compiler/reachabilityChecks11.ts] //// + +=== reachabilityChecks11.ts === +// while (true); +var x = 1; +>x : Symbol(x, Decl(reachabilityChecks11.ts, 1, 3)) + +module A { +>A : Symbol(A, Decl(reachabilityChecks11.ts, 1, 10)) + + while (true); + let x; +>x : Symbol(x, Decl(reachabilityChecks11.ts, 5, 7)) +} + +module A1 { +>A1 : Symbol(A1, Decl(reachabilityChecks11.ts, 6, 1)) + + do {} while(true); + module A { +>A : Symbol(A, Decl(reachabilityChecks11.ts, 9, 22)) + + interface F {} +>F : Symbol(F, Decl(reachabilityChecks11.ts, 10, 14)) + } +} + +module A2 { +>A2 : Symbol(A2, Decl(reachabilityChecks11.ts, 13, 1)) + + while (true); + module A { +>A : Symbol(A, Decl(reachabilityChecks11.ts, 16, 17)) + + var x = 1; +>x : Symbol(x, Decl(reachabilityChecks11.ts, 18, 11)) + } +} + +module A3 { +>A3 : Symbol(A3, Decl(reachabilityChecks11.ts, 20, 1)) + + while (true); + type T = string; +>T : Symbol(T, Decl(reachabilityChecks11.ts, 23, 17)) +} + +module A4 { +>A4 : Symbol(A4, Decl(reachabilityChecks11.ts, 25, 1)) + + while (true); + module A { +>A : Symbol(A, Decl(reachabilityChecks11.ts, 28, 17)) + + const enum E { X } +>E : Symbol(E, Decl(reachabilityChecks11.ts, 29, 14)) +>X : Symbol(E.X, Decl(reachabilityChecks11.ts, 30, 22)) + } +} + +function f1(x) { +>f1 : Symbol(f1, Decl(reachabilityChecks11.ts, 32, 1)) +>x : Symbol(x, Decl(reachabilityChecks11.ts, 34, 12), Decl(reachabilityChecks11.ts, 41, 7)) + + if (x) { +>x : Symbol(x, Decl(reachabilityChecks11.ts, 34, 12), Decl(reachabilityChecks11.ts, 41, 7)) + + return; + } + else { + throw new Error("123"); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } + var x; +>x : Symbol(x, Decl(reachabilityChecks11.ts, 34, 12), Decl(reachabilityChecks11.ts, 41, 7)) +} + +function f2() { +>f2 : Symbol(f2, Decl(reachabilityChecks11.ts, 42, 1)) + + return; + class A { +>A : Symbol(A, Decl(reachabilityChecks11.ts, 45, 11)) + } +} + +module B { +>B : Symbol(B, Decl(reachabilityChecks11.ts, 48, 1)) + + for (; ;); + module C { +>C : Symbol(C, Decl(reachabilityChecks11.ts, 51, 14)) + } +} + +function f3() { +>f3 : Symbol(f3, Decl(reachabilityChecks11.ts, 54, 1)) + + do { + } while (true); + enum E { +>E : Symbol(E, Decl(reachabilityChecks11.ts, 58, 19)) + + X = 1 +>X : Symbol(E.X, Decl(reachabilityChecks11.ts, 59, 12)) + } +} + +function f4() { +>f4 : Symbol(f4, Decl(reachabilityChecks11.ts, 62, 1)) + + if (true) { + throw new Error(); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } + const enum E { +>E : Symbol(E, Decl(reachabilityChecks11.ts, 67, 5)) + + X = 1 +>X : Symbol(E.X, Decl(reachabilityChecks11.ts, 68, 18)) + } +} + + diff --git a/tests/baselines/reference/reachabilityChecks11.types b/tests/baselines/reference/reachabilityChecks11.types new file mode 100644 index 0000000000000..49fcc60359573 --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks11.types @@ -0,0 +1,180 @@ +//// [tests/cases/compiler/reachabilityChecks11.ts] //// + +=== reachabilityChecks11.ts === +// while (true); +var x = 1; +>x : number +> : ^^^^^^ +>1 : 1 +> : ^ + +module A { +>A : typeof A +> : ^^^^^^^^ + + while (true); +>true : true +> : ^^^^ + + let x; +>x : any +> : ^^^ +} + +module A1 { +>A1 : typeof A1 +> : ^^^^^^^^^ + + do {} while(true); +>true : true +> : ^^^^ + + module A { + interface F {} + } +} + +module A2 { +>A2 : typeof A2 +> : ^^^^^^^^^ + + while (true); +>true : true +> : ^^^^ + + module A { +>A : typeof A +> : ^^^^^^^^ + + var x = 1; +>x : number +> : ^^^^^^ +>1 : 1 +> : ^ + } +} + +module A3 { +>A3 : typeof A3 +> : ^^^^^^^^^ + + while (true); +>true : true +> : ^^^^ + + type T = string; +>T : string +> : ^^^^^^ +} + +module A4 { +>A4 : typeof A4 +> : ^^^^^^^^^ + + while (true); +>true : true +> : ^^^^ + + module A { + const enum E { X } +>E : E +> : ^ +>X : E.X +> : ^^^ + } +} + +function f1(x) { +>f1 : (x: any) => void +> : ^ ^^^^^^^^^^^^^^ +>x : any +> : ^^^ + + if (x) { +>x : any +> : ^^^ + + return; + } + else { + throw new Error("123"); +>new Error("123") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"123" : "123" +> : ^^^^^ + } + var x; +>x : any +> : ^^^ +} + +function f2() { +>f2 : () => void +> : ^^^^^^^^^^ + + return; + class A { +>A : A +> : ^ + } +} + +module B { +>B : typeof B +> : ^^^^^^^^ + + for (; ;); + module C { + } +} + +function f3() { +>f3 : () => void +> : ^^^^^^^^^^ + + do { + } while (true); +>true : true +> : ^^^^ + + enum E { +>E : E +> : ^ + + X = 1 +>X : E.X +> : ^^^ +>1 : 1 +> : ^ + } +} + +function f4() { +>f4 : () => void +> : ^^^^^^^^^^ + + if (true) { +>true : true +> : ^^^^ + + throw new Error(); +>new Error() : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ + } + const enum E { +>E : E +> : ^ + + X = 1 +>X : E.X +> : ^^^ +>1 : 1 +> : ^ + } +} + + diff --git a/tests/baselines/reference/reachabilityChecks9.errors.txt b/tests/baselines/reference/reachabilityChecks9.errors.txt new file mode 100644 index 0000000000000..75b9cf98dac0e --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks9.errors.txt @@ -0,0 +1,37 @@ +reachabilityChecks9.ts(7,7): error TS7027: Unreachable code detected. +reachabilityChecks9.ts(20,7): error TS7027: Unreachable code detected. + + +==== reachabilityChecks9.ts (2 errors) ==== + // https://github.com/microsoft/TypeScript/issues/55562 + + function g(str: string) { + switch (str) { + case "a": + return; + console.log("1"); + ~~~~~~~~~~~~~~~~~ + console.log("2"); + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS7027: Unreachable code detected. + case "b": + console.log("3"); + } + } + + function h(str: string) { + switch (str) { + case "a": + console.log("1"); + default: + return; + console.log("2"); + ~~~~~~~~~~~~~~~~~ + console.log("3"); + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS7027: Unreachable code detected. + case "b": + console.log("4"); + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/reachabilityChecks9.symbols b/tests/baselines/reference/reachabilityChecks9.symbols new file mode 100644 index 0000000000000..d50f997b9aabc --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks9.symbols @@ -0,0 +1,65 @@ +//// [tests/cases/compiler/reachabilityChecks9.ts] //// + +=== reachabilityChecks9.ts === +// https://github.com/microsoft/TypeScript/issues/55562 + +function g(str: string) { +>g : Symbol(g, Decl(reachabilityChecks9.ts, 0, 0)) +>str : Symbol(str, Decl(reachabilityChecks9.ts, 2, 11)) + + switch (str) { +>str : Symbol(str, Decl(reachabilityChecks9.ts, 2, 11)) + + case "a": + return; + console.log("1"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + console.log("2"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + case "b": + console.log("3"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + } +} + +function h(str: string) { +>h : Symbol(h, Decl(reachabilityChecks9.ts, 11, 1)) +>str : Symbol(str, Decl(reachabilityChecks9.ts, 13, 11)) + + switch (str) { +>str : Symbol(str, Decl(reachabilityChecks9.ts, 13, 11)) + + case "a": + console.log("1"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + default: + return; + console.log("2"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + console.log("3"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + case "b": + console.log("4"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + } +} + diff --git a/tests/baselines/reference/reachabilityChecks9.types b/tests/baselines/reference/reachabilityChecks9.types new file mode 100644 index 0000000000000..d428078568a98 --- /dev/null +++ b/tests/baselines/reference/reachabilityChecks9.types @@ -0,0 +1,132 @@ +//// [tests/cases/compiler/reachabilityChecks9.ts] //// + +=== reachabilityChecks9.ts === +// https://github.com/microsoft/TypeScript/issues/55562 + +function g(str: string) { +>g : (str: string) => void +> : ^ ^^ ^^^^^^^^^ +>str : string +> : ^^^^^^ + + switch (str) { +>str : string +> : ^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + return; + console.log("1"); +>console.log("1") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"1" : "1" +> : ^^^ + + console.log("2"); +>console.log("2") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"2" : "2" +> : ^^^ + + case "b": +>"b" : "b" +> : ^^^ + + console.log("3"); +>console.log("3") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"3" : "3" +> : ^^^ + } +} + +function h(str: string) { +>h : (str: string) => void +> : ^ ^^ ^^^^^^^^^ +>str : string +> : ^^^^^^ + + switch (str) { +>str : string +> : ^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + console.log("1"); +>console.log("1") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"1" : "1" +> : ^^^ + + default: + return; + console.log("2"); +>console.log("2") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"2" : "2" +> : ^^^ + + console.log("3"); +>console.log("3") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"3" : "3" +> : ^^^ + + case "b": +>"b" : "b" +> : ^^^ + + console.log("4"); +>console.log("4") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"4" : "4" +> : ^^^ + } +} + diff --git a/tests/baselines/reference/reachabilityChecksIgnored.js b/tests/baselines/reference/reachabilityChecksIgnored.js new file mode 100644 index 0000000000000..20ea3147dd9a5 --- /dev/null +++ b/tests/baselines/reference/reachabilityChecksIgnored.js @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/reachabilityChecksIgnored.ts] //// + +//// [reachabilityChecksIgnored.ts] +function a() { + throw new Error(""); + + // @ts-ignore + console.log("unreachable"); +} + +function b() { + throw new Error(""); + + // @ts-expect-error + console.log("unreachable"); +} + +//// [reachabilityChecksIgnored.js] +function a() { + throw new Error(""); + // @ts-ignore + console.log("unreachable"); +} +function b() { + throw new Error(""); + // @ts-expect-error + console.log("unreachable"); +} diff --git a/tests/baselines/reference/reachabilityChecksIgnored.symbols b/tests/baselines/reference/reachabilityChecksIgnored.symbols new file mode 100644 index 0000000000000..e41bf5334309a --- /dev/null +++ b/tests/baselines/reference/reachabilityChecksIgnored.symbols @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/reachabilityChecksIgnored.ts] //// + +=== reachabilityChecksIgnored.ts === +function a() { +>a : Symbol(a, Decl(reachabilityChecksIgnored.ts, 0, 0)) + + throw new Error(""); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + // @ts-ignore + console.log("unreachable"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +} + +function b() { +>b : Symbol(b, Decl(reachabilityChecksIgnored.ts, 5, 1)) + + throw new Error(""); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + // @ts-expect-error + console.log("unreachable"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +} diff --git a/tests/baselines/reference/reachabilityChecksIgnored.types b/tests/baselines/reference/reachabilityChecksIgnored.types new file mode 100644 index 0000000000000..8b1798d5ce288 --- /dev/null +++ b/tests/baselines/reference/reachabilityChecksIgnored.types @@ -0,0 +1,54 @@ +//// [tests/cases/compiler/reachabilityChecksIgnored.ts] //// + +=== reachabilityChecksIgnored.ts === +function a() { +>a : () => void +> : ^^^^^^^^^^ + + throw new Error(""); +>new Error("") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"" : "" +> : ^^ + + // @ts-ignore + console.log("unreachable"); +>console.log("unreachable") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"unreachable" : "unreachable" +> : ^^^^^^^^^^^^^ +} + +function b() { +>b : () => void +> : ^^^^^^^^^^ + + throw new Error(""); +>new Error("") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"" : "" +> : ^^ + + // @ts-expect-error + console.log("unreachable"); +>console.log("unreachable") : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>"unreachable" : "unreachable" +> : ^^^^^^^^^^^^^ +} diff --git a/tests/cases/compiler/reachabilityChecks10.ts b/tests/cases/compiler/reachabilityChecks10.ts new file mode 100644 index 0000000000000..e4f17b935ce0f --- /dev/null +++ b/tests/cases/compiler/reachabilityChecks10.ts @@ -0,0 +1,7 @@ +// @strict: true +// @noEmit: true +// @allowUnreachableCode: false + +throw new Error("") +console.log("1") +console.log("2") diff --git a/tests/cases/compiler/reachabilityChecks11.ts b/tests/cases/compiler/reachabilityChecks11.ts new file mode 100644 index 0000000000000..81dbcf3c7ad81 --- /dev/null +++ b/tests/cases/compiler/reachabilityChecks11.ts @@ -0,0 +1,76 @@ +// @allowUnreachableCode: false +// @preserveConstEnums: true + +// while (true); +var x = 1; + +module A { + while (true); + let x; +} + +module A1 { + do {} while(true); + module A { + interface F {} + } +} + +module A2 { + while (true); + module A { + var x = 1; + } +} + +module A3 { + while (true); + type T = string; +} + +module A4 { + while (true); + module A { + const enum E { X } + } +} + +function f1(x) { + if (x) { + return; + } + else { + throw new Error("123"); + } + var x; +} + +function f2() { + return; + class A { + } +} + +module B { + for (; ;); + module C { + } +} + +function f3() { + do { + } while (true); + enum E { + X = 1 + } +} + +function f4() { + if (true) { + throw new Error(); + } + const enum E { + X = 1 + } +} + diff --git a/tests/cases/compiler/reachabilityChecks9.ts b/tests/cases/compiler/reachabilityChecks9.ts new file mode 100644 index 0000000000000..601cdb65d4abd --- /dev/null +++ b/tests/cases/compiler/reachabilityChecks9.ts @@ -0,0 +1,29 @@ +// @strict: true +// @noEmit: true +// @allowUnreachableCode: false + +// https://github.com/microsoft/TypeScript/issues/55562 + +function g(str: string) { + switch (str) { + case "a": + return; + console.log("1"); + console.log("2"); + case "b": + console.log("3"); + } +} + +function h(str: string) { + switch (str) { + case "a": + console.log("1"); + default: + return; + console.log("2"); + console.log("3"); + case "b": + console.log("4"); + } +} diff --git a/tests/cases/compiler/reachabilityChecksIgnored.ts b/tests/cases/compiler/reachabilityChecksIgnored.ts new file mode 100644 index 0000000000000..baf32b57894d0 --- /dev/null +++ b/tests/cases/compiler/reachabilityChecksIgnored.ts @@ -0,0 +1,17 @@ +// @allowUnreachableCode: false +// @preserveConstEnums: true + + +function a() { + throw new Error(""); + + // @ts-ignore + console.log("unreachable"); +} + +function b() { + throw new Error(""); + + // @ts-expect-error + console.log("unreachable"); +} \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUnreachableCode_noSuggestionIfDisabled.ts b/tests/cases/fourslash/codeFixUnreachableCode_noSuggestionIfDisabled.ts index 35ad3c430a335..8027f00275d96 100644 --- a/tests/cases/fourslash/codeFixUnreachableCode_noSuggestionIfDisabled.ts +++ b/tests/cases/fourslash/codeFixUnreachableCode_noSuggestionIfDisabled.ts @@ -2,6 +2,6 @@ // @allowUnreachableCode: true -////if (false) 0; +////if (false) [|0;|] verify.getSuggestionDiagnostics([]); diff --git a/tests/cases/fourslash/codeFixUnusedLabel_noSuggestionIfDisabled.ts b/tests/cases/fourslash/codeFixUnusedLabel_noSuggestionIfDisabled.ts index a7e504d2f66dd..e1a69b5bf3198 100644 --- a/tests/cases/fourslash/codeFixUnusedLabel_noSuggestionIfDisabled.ts +++ b/tests/cases/fourslash/codeFixUnusedLabel_noSuggestionIfDisabled.ts @@ -2,6 +2,6 @@ // @allowUnusedLabels: true -////foo: while (true) {} +////[|foo|]: while (true) {} verify.getSuggestionDiagnostics([]);