From 55f4b02ed4a75087ce22ad9a0c54cbe668c14ced Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 2 Mar 2016 14:25:55 -0800 Subject: [PATCH 001/110] Enable rename on all projects for a file --- src/server/session.ts | 101 ++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/src/server/session.ts b/src/server/session.ts index f0975a3f947..db5511c0174 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -412,14 +412,15 @@ namespace ts.server { private getRenameLocations(line: number, offset: number, fileName: string, findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { const file = ts.normalizePath(fileName); - const project = this.projectService.getProjectForFile(file); - if (!project) { + const defaultProject = this.projectService.getProjectForFile(file); + if (!defaultProject) { throw Errors.NoProject; } - const compilerService = project.compilerService; - const position = compilerService.host.lineOffsetToPosition(file, line, offset); - const renameInfo = compilerService.languageService.getRenameInfo(file, position); + // The rename info should be the same for every project + const defaultProjectCompilerService = defaultProject.compilerService; + const position = defaultProjectCompilerService.host.lineOffsetToPosition(file, line, offset); + const renameInfo = defaultProjectCompilerService.languageService.getRenameInfo(file, position); if (!renameInfo) { return undefined; } @@ -431,51 +432,65 @@ namespace ts.server { }; } - const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments); - if (!renameLocations) { - return undefined; - } + const locsMap: Map = {}; + const info = this.projectService.getScriptInfo(file); + const projects = this.projectService.findReferencingProjects(info); + for (const project of projects) { + const compilerService = project.compilerService; + const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments); + if (!renameLocations) { + continue; + } - const bakedRenameLocs = renameLocations.map(location => ({ - file: location.fileName, - start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start), - end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)), - })).sort((a, b) => { - if (a.file < b.file) { - return -1; - } - else if (a.file > b.file) { - return 1; - } - else { - // reverse sort assuming no overlap - if (a.start.line < b.start.line) { - return 1; - } - else if (a.start.line > b.start.line) { + const bakedRenameLocs = renameLocations.map(location => ({ + file: location.fileName, + start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start), + end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)), + })).sort((a, b) => { + if (a.file < b.file) { return -1; } + else if (a.file > b.file) { + return 1; + } else { - return b.start.offset - a.start.offset; + // reverse sort assuming no overlap + if (a.start.line < b.start.line) { + return 1; + } + else if (a.start.line > b.start.line) { + return -1; + } + else { + return b.start.offset - a.start.offset; + } } - } - }).reduce((accum: protocol.SpanGroup[], cur: protocol.FileSpan) => { - let curFileAccum: protocol.SpanGroup; - if (accum.length > 0) { - curFileAccum = accum[accum.length - 1]; - if (curFileAccum.file != cur.file) { - curFileAccum = undefined; + }).reduce((accum: protocol.SpanGroup[], cur: protocol.FileSpan) => { + let curFileAccum: protocol.SpanGroup; + if (accum.length > 0) { + curFileAccum = accum[accum.length - 1]; + if (curFileAccum.file != cur.file) { + curFileAccum = undefined; + } } - } - if (!curFileAccum) { - curFileAccum = { file: cur.file, locs: [] }; - accum.push(curFileAccum); - } - curFileAccum.locs.push({ start: cur.start, end: cur.end }); - return accum; - }, []); + if (!curFileAccum) { + curFileAccum = { file: cur.file, locs: [] }; + accum.push(curFileAccum); + } + curFileAccum.locs.push({ start: cur.start, end: cur.end }); + return accum; + }, []); - return { info: renameInfo, locs: bakedRenameLocs }; + for (const bakedRenameLoc of bakedRenameLocs) { + locsMap[bakedRenameLoc.file] = bakedRenameLoc; + } + } + + const locs: protocol.SpanGroup[] = []; + for (const key in locsMap) { + locs.push(locsMap[key]); + } + return { info: renameInfo, locs }; } private getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody { From 7663a96a7b45afb90a0a86412b75f5b5466a81ba Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 2 Mar 2016 15:36:47 -0800 Subject: [PATCH 002/110] Enable findReferences on all projects for a file --- src/compiler/core.ts | 13 +++++-- src/server/session.ts | 91 +++++++++++++++++++++++++------------------ 2 files changed, 63 insertions(+), 41 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 702ded96a3f..df8e3d1bce4 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -91,10 +91,15 @@ namespace ts { return undefined; } - export function contains(array: T[], value: T): boolean { + export function contains(array: T[], value: T, areEqual?: (a: T, b: T) => boolean): boolean { if (array) { for (const v of array) { - if (v === value) { + if (areEqual) { + if (areEqual(v, value)) { + return true; + } + } + else if (v === value) { return true; } } @@ -156,12 +161,12 @@ namespace ts { return array1.concat(array2); } - export function deduplicate(array: T[]): T[] { + export function deduplicate(array: T[], areEqual?: (a: T, b: T) => boolean): T[] { let result: T[]; if (array) { result = []; for (const item of array) { - if (!contains(result, item)) { + if (!contains(result, item, areEqual)) { result.push(item); } } diff --git a/src/server/session.ts b/src/server/session.ts index db5511c0174..bfb3e9154b1 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -432,7 +432,7 @@ namespace ts.server { }; } - const locsMap: Map = {}; + const locs: protocol.SpanGroup[] = []; const info = this.projectService.getScriptInfo(file); const projects = this.projectService.findReferencingProjects(info); for (const project of projects) { @@ -481,63 +481,80 @@ namespace ts.server { return accum; }, []); - for (const bakedRenameLoc of bakedRenameLocs) { - locsMap[bakedRenameLoc.file] = bakedRenameLoc; - } + ts.addRange(locs, bakedRenameLocs); } - const locs: protocol.SpanGroup[] = []; - for (const key in locsMap) { - locs.push(locsMap[key]); + return { info: renameInfo, locs: ts.deduplicate(locs, areSpanGroupsForTheSameFile) }; + + function areSpanGroupsForTheSameFile(a: protocol.SpanGroup, b: protocol.SpanGroup) { + if (a && b) { + return a.file === b.file; + } + return false; } - return { info: renameInfo, locs }; } private getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody { - // TODO: get all projects for this file; report refs for all projects deleting duplicates - // can avoid duplicates by eliminating same ref file from subsequent projects const file = ts.normalizePath(fileName); - const project = this.projectService.getProjectForFile(file); - if (!project) { + const defaultProject = this.projectService.getProjectForFile(file); + if (!defaultProject) { throw Errors.NoProject; } - const compilerService = project.compilerService; - const position = compilerService.host.lineOffsetToPosition(file, line, offset); - - const references = compilerService.languageService.getReferencesAtPosition(file, position); - if (!references) { - return undefined; - } - - const nameInfo = compilerService.languageService.getQuickInfoAtPosition(file, position); + const position = defaultProject.compilerService.host.lineOffsetToPosition(file, line, offset); + const nameInfo = defaultProject.compilerService.languageService.getQuickInfoAtPosition(file, position); if (!nameInfo) { return undefined; } const displayString = ts.displayPartsToString(nameInfo.displayParts); const nameSpan = nameInfo.textSpan; - const nameColStart = compilerService.host.positionToLineOffset(file, nameSpan.start).offset; - const nameText = compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); - const bakedRefs: protocol.ReferencesResponseItem[] = references.map(ref => { - const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start); - const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1); - const snap = compilerService.host.getScriptSnapshot(ref.fileName); - const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); - return { - file: ref.fileName, - start: start, - lineText: lineText, - end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)), - isWriteAccess: ref.isWriteAccess - }; - }).sort(compareFileStart); + const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset; + const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); + + const info = this.projectService.getScriptInfo(file); + const projects = this.projectService.findReferencingProjects(info); + const refs: protocol.ReferencesResponseItem[] = []; + for (const project of projects) + { + const compilerService = project.compilerService; + const references = compilerService.languageService.getReferencesAtPosition(file, position); + if (!references) { + continue; + } + + const bakedRefs: protocol.ReferencesResponseItem[] = references.map(ref => { + const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start); + const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1); + const snap = compilerService.host.getScriptSnapshot(ref.fileName); + const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); + return { + file: ref.fileName, + start: start, + lineText: lineText, + end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)), + isWriteAccess: ref.isWriteAccess + }; + }).sort(compareFileStart); + + ts.addRange(refs, bakedRefs); + } + return { - refs: bakedRefs, + refs: ts.deduplicate(refs, areReferencesResponseItemsForTheSameLocation), symbolName: nameText, symbolStartOffset: nameColStart, symbolDisplayString: displayString }; + + function areReferencesResponseItemsForTheSameLocation(a: protocol.ReferencesResponseItem, b: protocol.ReferencesResponseItem) { + if (a && b) { + return a.file === b.file && + a.start === b.start && + a.end === b.end; + } + return false; + } } /** From 2835e259aa05873256006ef1631f184b762ad048 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 2 Mar 2016 15:50:00 -0800 Subject: [PATCH 003/110] Enable navigateTo on all projects for a file --- src/server/session.ts | 84 +++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/src/server/session.ts b/src/server/session.ts index bfb3e9154b1..199e6df21f4 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -481,10 +481,10 @@ namespace ts.server { return accum; }, []); - ts.addRange(locs, bakedRenameLocs); + addRange(locs, bakedRenameLocs); } - return { info: renameInfo, locs: ts.deduplicate(locs, areSpanGroupsForTheSameFile) }; + return { info: renameInfo, locs: deduplicate(locs, areSpanGroupsForTheSameFile) }; function areSpanGroupsForTheSameFile(a: protocol.SpanGroup, b: protocol.SpanGroup) { if (a && b) { @@ -537,11 +537,11 @@ namespace ts.server { }; }).sort(compareFileStart); - ts.addRange(refs, bakedRefs); + addRange(refs, bakedRefs); } return { - refs: ts.deduplicate(refs, areReferencesResponseItemsForTheSameLocation), + refs: deduplicate(refs, areReferencesResponseItemsForTheSameLocation), symbolName: nameText, symbolStartOffset: nameColStart, symbolDisplayString: displayString @@ -868,41 +868,57 @@ namespace ts.server { private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] { const file = ts.normalizePath(fileName); - const project = this.projectService.getProjectForFile(file); - if (!project) { + const defaultProject = this.projectService.getProjectForFile(file); + if (!defaultProject) { throw Errors.NoProject; } - const compilerService = project.compilerService; - const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount); - if (!navItems) { - return undefined; - } + const info = this.projectService.getScriptInfo(file); + const projects = this.projectService.findReferencingProjects(info); + const allNavToItems: protocol.NavtoItem[] = []; + for (const project of projects) { + const compilerService = project.compilerService; + const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount); + if (!navItems) { + continue; + } - return navItems.map((navItem) => { - const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start); - const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); - const bakedItem: protocol.NavtoItem = { - name: navItem.name, - kind: navItem.kind, - file: navItem.fileName, - start: start, - end: end, - }; - if (navItem.kindModifiers && (navItem.kindModifiers != "")) { - bakedItem.kindModifiers = navItem.kindModifiers; + const bakedNavItems = navItems.map((navItem) => { + const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start); + const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); + const bakedItem: protocol.NavtoItem = { + name: navItem.name, + kind: navItem.kind, + file: navItem.fileName, + start: start, + end: end, + }; + if (navItem.kindModifiers && (navItem.kindModifiers != "")) { + bakedItem.kindModifiers = navItem.kindModifiers; + } + if (navItem.matchKind !== "none") { + bakedItem.matchKind = navItem.matchKind; + } + if (navItem.containerName && (navItem.containerName.length > 0)) { + bakedItem.containerName = navItem.containerName; + } + if (navItem.containerKind && (navItem.containerKind.length > 0)) { + bakedItem.containerKind = navItem.containerKind; + } + return bakedItem; + }); + addRange(allNavToItems, bakedNavItems); + } + return deduplicate(allNavToItems, areNavToItemsForTheSameLocation); + + function areNavToItemsForTheSameLocation(a: protocol.NavtoItem, b: protocol.NavtoItem) { + if (a && b) { + return a.file === b.file && + a.start === b.start && + a.end === b.end; } - if (navItem.matchKind !== "none") { - bakedItem.matchKind = navItem.matchKind; - } - if (navItem.containerName && (navItem.containerName.length > 0)) { - bakedItem.containerName = navItem.containerName; - } - if (navItem.containerKind && (navItem.containerKind.length > 0)) { - bakedItem.containerKind = navItem.containerKind; - } - return bakedItem; - }); + return false; + } } private getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] { From 8294a18150cdb39e89ffa9b46f60407f26db7bd2 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 2 Mar 2016 16:13:52 -0800 Subject: [PATCH 004/110] Add tests --- .../findReferencesAcrossMultipleProjects.ts | 17 +++++++++++++++++ .../goToDefinitionAcrossMultipleProjects.ts | 17 +++++++++++++++++ .../fourslash/renameAcrossMultipleProjects.ts | 17 +++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 tests/cases/fourslash/findReferencesAcrossMultipleProjects.ts create mode 100644 tests/cases/fourslash/goToDefinitionAcrossMultipleProjects.ts create mode 100644 tests/cases/fourslash/renameAcrossMultipleProjects.ts diff --git a/tests/cases/fourslash/findReferencesAcrossMultipleProjects.ts b/tests/cases/fourslash/findReferencesAcrossMultipleProjects.ts new file mode 100644 index 00000000000..0ef7745f8f9 --- /dev/null +++ b/tests/cases/fourslash/findReferencesAcrossMultipleProjects.ts @@ -0,0 +1,17 @@ +/// + +//@Filename: a.ts +////var /*1*/x: number; + +//@Filename: b.ts +/////// +////x++; + +//@Filename: c.ts +/////// +////x++; + +goTo.file("a.ts"); +goTo.marker("1"); + +verify.referencesCountIs(3); \ No newline at end of file diff --git a/tests/cases/fourslash/goToDefinitionAcrossMultipleProjects.ts b/tests/cases/fourslash/goToDefinitionAcrossMultipleProjects.ts new file mode 100644 index 00000000000..bac47638be6 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionAcrossMultipleProjects.ts @@ -0,0 +1,17 @@ +/// + +//@Filename: a.ts +////var x: number; + +//@Filename: b.ts +////var x: number; + +//@Filename: c.ts +/////// +/////// +/////**/x++; + +goTo.file("c.ts"); +goTo.marker(); + +verify.definitionCountIs(2); \ No newline at end of file diff --git a/tests/cases/fourslash/renameAcrossMultipleProjects.ts b/tests/cases/fourslash/renameAcrossMultipleProjects.ts new file mode 100644 index 00000000000..44b5c0baef4 --- /dev/null +++ b/tests/cases/fourslash/renameAcrossMultipleProjects.ts @@ -0,0 +1,17 @@ +/// + +//@Filename: a.ts +////var /*1*/[|x|]: number; + +//@Filename: b.ts +/////// +////[|x|]++; + +//@Filename: c.ts +/////// +////[|x|]++; + +goTo.file("a.ts"); +goTo.marker("1"); + +verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false); \ No newline at end of file From e67d15a1ce0503672c4d0e37bd3faadbb78ee98c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Mar 2016 10:20:43 -0700 Subject: [PATCH 005/110] Initial implementation of control flow based type analysis --- src/compiler/binder.ts | 720 ++++++++++++++++++++++++---------------- src/compiler/checker.ts | 492 +++++++++++---------------- src/compiler/types.ts | 34 ++ 3 files changed, 662 insertions(+), 584 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 6957be484f3..b49e22e8192 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -11,19 +11,11 @@ namespace ts { ConstEnumOnly = 2 } - const enum Reachability { - Uninitialized = 1 << 0, - Reachable = 1 << 1, - Unreachable = 1 << 2, - ReportedUnreachable = 1 << 3 - } - - function or(state1: Reachability, state2: Reachability): Reachability { - return (state1 | state2) & Reachability.Reachable - ? Reachability.Reachable - : (state1 & state2) & Reachability.ReportedUnreachable - ? Reachability.ReportedUnreachable - : Reachability.Unreachable; + interface ActiveLabel { + name: string; + breakTarget: FlowLabel; + continueTarget: FlowLabel; + referenced: boolean; } export function getModuleInstanceState(node: Node): ModuleInstanceState { @@ -112,10 +104,11 @@ namespace ts { // state used by reachability checks let hasExplicitReturn: boolean; - let currentReachabilityState: Reachability; - let labelStack: Reachability[]; - let labelIndexMap: Map; - let implicitLabels: number[]; + let currentFlow: FlowNode; + let breakTarget: FlowLabel; + let continueTarget: FlowLabel; + let preSwitchCaseFlow: FlowNode; + let activeLabels: ActiveLabel[]; // state used for emit helpers let hasClassExtends: boolean; @@ -132,6 +125,9 @@ namespace ts { let Symbol: { new (flags: SymbolFlags, name: string): Symbol }; let classifiableNames: Map; + const unreachableFlow: FlowNode = { kind: FlowKind.Unreachable }; + const reportedUncreachableFlow: FlowNode = { kind: FlowKind.Unreachable }; + function bindSourceFile(f: SourceFile, opts: CompilerOptions) { file = f; options = opts; @@ -154,9 +150,10 @@ namespace ts { lastContainer = undefined; seenThisKeyword = false; hasExplicitReturn = false; - labelStack = undefined; - labelIndexMap = undefined; - implicitLabels = undefined; + currentFlow = undefined; + breakTarget = undefined; + continueTarget = undefined; + activeLabels = undefined; hasClassExtends = false; hasAsyncFunctions = false; hasDecorators = false; @@ -436,11 +433,11 @@ namespace ts { blockScopeContainer.locals = undefined; } - let savedReachabilityState: Reachability; - let savedLabelStack: Reachability[]; - let savedLabels: Map; - let savedImplicitLabels: number[]; let savedHasExplicitReturn: boolean; + let savedCurrentFlow: FlowNode; + let savedBreakTarget: FlowLabel; + let savedContinueTarget: FlowLabel; + let savedActiveLabels: ActiveLabel[]; const kind = node.kind; let flags = node.flags; @@ -457,15 +454,17 @@ namespace ts { const saveState = kind === SyntaxKind.SourceFile || kind === SyntaxKind.ModuleBlock || isFunctionLikeKind(kind); if (saveState) { - savedReachabilityState = currentReachabilityState; - savedLabelStack = labelStack; - savedLabels = labelIndexMap; - savedImplicitLabels = implicitLabels; savedHasExplicitReturn = hasExplicitReturn; + savedCurrentFlow = currentFlow; + savedBreakTarget = breakTarget; + savedContinueTarget = continueTarget; + savedActiveLabels = activeLabels; - currentReachabilityState = Reachability.Reachable; hasExplicitReturn = false; - labelStack = labelIndexMap = implicitLabels = undefined; + currentFlow = { kind: FlowKind.Start }; + breakTarget = undefined; + continueTarget = undefined; + activeLabels = undefined; } if (isInJavaScriptFile(node) && node.jsDocComment) { @@ -474,7 +473,7 @@ namespace ts { bindReachableStatement(node); - if (currentReachabilityState === Reachability.Reachable && isFunctionLikeKind(kind) && nodeIsPresent((node).body)) { + if (currentFlow.kind !== FlowKind.Unreachable && isFunctionLikeKind(kind) && nodeIsPresent((node).body)) { flags |= NodeFlags.HasImplicitReturn; if (hasExplicitReturn) { flags |= NodeFlags.HasExplicitReturn; @@ -503,11 +502,11 @@ namespace ts { node.flags = flags; if (saveState) { + activeLabels = savedActiveLabels; + continueTarget = savedContinueTarget; + breakTarget = savedBreakTarget; + currentFlow = savedCurrentFlow; hasExplicitReturn = savedHasExplicitReturn; - currentReachabilityState = savedReachabilityState; - labelStack = savedLabelStack; - labelIndexMap = savedLabels; - implicitLabels = savedImplicitLabels; } container = saveContainer; @@ -562,174 +561,381 @@ namespace ts { case SyntaxKind.LabeledStatement: bindLabeledStatement(node); break; + case SyntaxKind.BinaryExpression: + bindBinaryExpressionFlow(node); + break; + case SyntaxKind.ConditionalExpression: + bindConditionalExpressionFlow(node); + break; + case SyntaxKind.VariableDeclaration: + bindVariableDeclarationFlow(node); + break; default: forEachChild(node, bind); break; } } - function bindWhileStatement(n: WhileStatement): void { - const preWhileState = - n.expression.kind === SyntaxKind.FalseKeyword ? Reachability.Unreachable : currentReachabilityState; - const postWhileState = - n.expression.kind === SyntaxKind.TrueKeyword ? Reachability.Unreachable : currentReachabilityState; - - // bind expressions (don't affect reachability) - bind(n.expression); - - currentReachabilityState = preWhileState; - const postWhileLabel = pushImplicitLabel(); - bind(n.statement); - popImplicitLabel(postWhileLabel, postWhileState); + function isNarrowableReference(expr: Expression): boolean { + return expr.kind === SyntaxKind.Identifier || + expr.kind === SyntaxKind.ThisKeyword || + expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((expr).expression); } - function bindDoStatement(n: DoStatement): void { - const preDoState = currentReachabilityState; - - const postDoLabel = pushImplicitLabel(); - bind(n.statement); - const postDoState = n.expression.kind === SyntaxKind.TrueKeyword ? Reachability.Unreachable : preDoState; - popImplicitLabel(postDoLabel, postDoState); - - // bind expressions (don't affect reachability) - bind(n.expression); - } - - function bindForStatement(n: ForStatement): void { - const preForState = currentReachabilityState; - const postForLabel = pushImplicitLabel(); - - // bind expressions (don't affect reachability) - bind(n.initializer); - bind(n.condition); - bind(n.incrementor); - - bind(n.statement); - - // for statement is considered infinite when it condition is either omitted or is true keyword - // - for(..;;..) - // - for(..;true;..) - const isInfiniteLoop = (!n.condition || n.condition.kind === SyntaxKind.TrueKeyword); - const postForState = isInfiniteLoop ? Reachability.Unreachable : preForState; - popImplicitLabel(postForLabel, postForState); - } - - function bindForInOrForOfStatement(n: ForInStatement | ForOfStatement): void { - const preStatementState = currentReachabilityState; - const postStatementLabel = pushImplicitLabel(); - - // bind expressions (don't affect reachability) - bind(n.initializer); - bind(n.expression); - - bind(n.statement); - popImplicitLabel(postStatementLabel, preStatementState); - } - - function bindIfStatement(n: IfStatement): void { - // denotes reachability state when entering 'thenStatement' part of the if statement: - // i.e. if condition is false then thenStatement is unreachable - const ifTrueState = n.expression.kind === SyntaxKind.FalseKeyword ? Reachability.Unreachable : currentReachabilityState; - // denotes reachability state when entering 'elseStatement': - // i.e. if condition is true then elseStatement is unreachable - const ifFalseState = n.expression.kind === SyntaxKind.TrueKeyword ? Reachability.Unreachable : currentReachabilityState; - - currentReachabilityState = ifTrueState; - - // bind expression (don't affect reachability) - bind(n.expression); - - bind(n.thenStatement); - if (n.elseStatement) { - const preElseState = currentReachabilityState; - currentReachabilityState = ifFalseState; - bind(n.elseStatement); - currentReachabilityState = or(currentReachabilityState, preElseState); + function isNarrowingExpression(expr: Expression): boolean { + switch (expr.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.ThisKeyword: + case SyntaxKind.PropertyAccessExpression: + return isNarrowableReference(expr); + case SyntaxKind.CallExpression: + return true; + case SyntaxKind.ParenthesizedExpression: + return isNarrowingExpression((expr).expression); + case SyntaxKind.BinaryExpression: + return isNarrowingBinaryExpression(expr); + case SyntaxKind.PrefixUnaryExpression: + return (expr).operator === SyntaxKind.ExclamationToken && isNarrowingExpression((expr).operand); } - else { - currentReachabilityState = or(currentReachabilityState, ifFalseState); + return false; + } + + function isNarrowingBinaryExpression(expr: BinaryExpression) { + switch (expr.operatorToken.kind) { + case SyntaxKind.EqualsEqualsToken: + case SyntaxKind.ExclamationEqualsToken: + case SyntaxKind.EqualsEqualsEqualsToken: + case SyntaxKind.ExclamationEqualsEqualsToken: + if (isNarrowingExpression(expr.left) && (expr.right.kind === SyntaxKind.NullKeyword || expr.right.kind === SyntaxKind.Identifier)) { + return true; + } + if (expr.left.kind === SyntaxKind.TypeOfExpression && isNarrowingExpression((expr.left).expression) && expr.right.kind === SyntaxKind.StringLiteral) { + return true; + } + return false; + case SyntaxKind.AmpersandAmpersandToken: + case SyntaxKind.BarBarToken: + return isNarrowingExpression(expr.left) || isNarrowingExpression(expr.right); + case SyntaxKind.InstanceOfKeyword: + return isNarrowingExpression(expr.left); + } + return false; + } + + function createFlowLabel(): FlowLabel { + return { + kind: FlowKind.Label, + antecedents: undefined + }; + } + + function addAntecedent(label: FlowLabel, antecedent: FlowNode): void { + if (antecedent.kind !== FlowKind.Unreachable && !contains(label.antecedents, antecedent)) { + (label.antecedents || (label.antecedents = [])).push(antecedent); } } - function bindReturnOrThrow(n: ReturnStatement | ThrowStatement): void { - // bind expression (don't affect reachability) - bind(n.expression); - if (n.kind === SyntaxKind.ReturnStatement) { + function createFlowCondition(antecedent: FlowNode, expression: Expression, assumeTrue: boolean): FlowNode { + if (!expression) { + return assumeTrue ? antecedent : unreachableFlow; + } + if (expression.kind === SyntaxKind.TrueKeyword && !assumeTrue || expression.kind === SyntaxKind.FalseKeyword && assumeTrue) { + return unreachableFlow; + } + if (!isNarrowingExpression(expression)) { + return antecedent; + } + return { + kind: FlowKind.Condition, + antecedent, + expression, + assumeTrue + }; + } + + function createFlowAssignment(antecedent: FlowNode, node: BinaryExpression | VariableDeclaration | ForInStatement | ForOfStatement): FlowNode { + return { + kind: FlowKind.Assignment, + antecedent, + node + }; + } + + function finishFlow(flow: FlowNode): FlowNode { + while (flow.kind === FlowKind.Label) { + const antecedents = (flow).antecedents; + if (!antecedents) { + return unreachableFlow; + } + if (antecedents.length > 1) { + break; + } + flow = antecedents[0]; + } + return flow; + } + + function bindWhileStatement(node: WhileStatement): void { + const preWhileLabel = createFlowLabel(); + const postWhileLabel = createFlowLabel(); + addAntecedent(preWhileLabel, currentFlow); + currentFlow = preWhileLabel; + bind(node.expression); + addAntecedent(postWhileLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ false)); + currentFlow = createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ true); + const saveBreakTarget = breakTarget; + const saveContinueTarget = continueTarget; + breakTarget = postWhileLabel; + continueTarget = preWhileLabel; + bind(node.statement); + breakTarget = saveBreakTarget; + continueTarget = saveContinueTarget; + addAntecedent(preWhileLabel, currentFlow); + currentFlow = finishFlow(postWhileLabel); + } + + function bindDoStatement(node: DoStatement): void { + const preDoLabel = createFlowLabel(); + const postDoLabel = createFlowLabel(); + addAntecedent(preDoLabel, currentFlow); + currentFlow = preDoLabel; + const saveBreakTarget = breakTarget; + const saveContinueTarget = continueTarget; + breakTarget = postDoLabel; + continueTarget = preDoLabel; + bind(node.statement); + breakTarget = saveBreakTarget; + continueTarget = saveContinueTarget; + bind(node.expression); + addAntecedent(preDoLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ true)); + addAntecedent(postDoLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ false)); + currentFlow = finishFlow(postDoLabel); + } + + function bindForStatement(node: ForStatement): void { + const preLoopLabel = createFlowLabel(); + const postLoopLabel = createFlowLabel(); + bind(node.initializer); + addAntecedent(preLoopLabel, currentFlow); + currentFlow = preLoopLabel; + bind(node.condition); + addAntecedent(postLoopLabel, createFlowCondition(currentFlow, node.condition, /*assumeTrue*/ false)); + currentFlow = createFlowCondition(currentFlow, node.condition, /*assumeTrue*/ true); + const saveBreakTarget = breakTarget; + const saveContinueTarget = continueTarget; + breakTarget = postLoopLabel; + continueTarget = preLoopLabel; + bind(node.statement); + bind(node.incrementor); + breakTarget = saveBreakTarget; + continueTarget = saveContinueTarget; + addAntecedent(preLoopLabel, currentFlow); + currentFlow = finishFlow(postLoopLabel); + } + + function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void { + const preLoopLabel = createFlowLabel(); + const postLoopLabel = createFlowLabel(); + bind(node.initializer); + bind(node.expression); + addAntecedent(preLoopLabel, currentFlow); + addAntecedent(postLoopLabel, currentFlow); + currentFlow = preLoopLabel; + const saveBreakTarget = breakTarget; + const saveContinueTarget = continueTarget; + breakTarget = postLoopLabel; + continueTarget = preLoopLabel; + currentFlow = createFlowAssignment(currentFlow, node); + bind(node.statement); + breakTarget = saveBreakTarget; + continueTarget = saveContinueTarget; + addAntecedent(preLoopLabel, currentFlow); + addAntecedent(postLoopLabel, currentFlow); + currentFlow = finishFlow(postLoopLabel); + } + + function bindIfStatement(node: IfStatement): void { + const postIfLabel = createFlowLabel(); + bind(node.expression); + const postConditionFlow = currentFlow; + currentFlow = createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ true); + bind(node.thenStatement); + addAntecedent(postIfLabel, currentFlow); + currentFlow = createFlowCondition(postConditionFlow, node.expression, /*assumeTrue*/ false); + bind(node.elseStatement); + addAntecedent(postIfLabel, currentFlow); + currentFlow = finishFlow(postIfLabel); + } + + function bindReturnOrThrow(node: ReturnStatement | ThrowStatement): void { + bind(node.expression); + if (node.kind === SyntaxKind.ReturnStatement) { hasExplicitReturn = true; } - currentReachabilityState = Reachability.Unreachable; + currentFlow = unreachableFlow; } - function bindBreakOrContinueStatement(n: BreakOrContinueStatement): void { - // call bind on label (don't affect reachability) - bind(n.label); - // for continue case touch label so it will be marked a used - const isValidJump = jumpToLabel(n.label, n.kind === SyntaxKind.BreakStatement ? currentReachabilityState : Reachability.Unreachable); - if (isValidJump) { - currentReachabilityState = Reachability.Unreachable; + function findActiveLabel(name: string) { + if (activeLabels) { + for (const label of activeLabels) { + if (label.name === name) { + return label; + } + } + } + return undefined; + } + + function bindbreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel, continueTarget: FlowLabel) { + const flowLabel = node.kind === SyntaxKind.BreakStatement ? breakTarget : continueTarget; + if (flowLabel) { + addAntecedent(flowLabel, currentFlow); + currentFlow = unreachableFlow; } } - function bindTryStatement(n: TryStatement): void { - // catch\finally blocks has the same reachability as try block - const preTryState = currentReachabilityState; - bind(n.tryBlock); - const postTryState = currentReachabilityState; - - currentReachabilityState = preTryState; - bind(n.catchClause); - const postCatchState = currentReachabilityState; - - currentReachabilityState = preTryState; - bind(n.finallyBlock); - - // post catch/finally state is reachable if - // - post try state is reachable - control flow can fall out of try block - // - post catch state is reachable - control flow can fall out of catch block - currentReachabilityState = n.catchClause ? or(postTryState, postCatchState) : postTryState; + function bindBreakOrContinueStatement(node: BreakOrContinueStatement): void { + bind(node.label); + if (node.label) { + const activeLabel = findActiveLabel(node.label.text); + if (activeLabel) { + activeLabel.referenced = true; + bindbreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget); + } + } + else { + bindbreakOrContinueFlow(node, breakTarget, continueTarget); + } } - function bindSwitchStatement(n: SwitchStatement): void { - const preSwitchState = currentReachabilityState; - const postSwitchLabel = pushImplicitLabel(); - - // bind expression (don't affect reachability) - bind(n.expression); - - bind(n.caseBlock); - - const hasDefault = forEach(n.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause); - - // post switch state is unreachable if switch is exhaustive (has a default case ) and does not have fallthrough from the last case - const postSwitchState = hasDefault && currentReachabilityState !== Reachability.Reachable ? Reachability.Unreachable : preSwitchState; - - popImplicitLabel(postSwitchLabel, postSwitchState); + function bindTryStatement(node: TryStatement): void { + const postFinallyLabel = createFlowLabel(); + const preTryFlow = currentFlow; + // TODO: Every statement in try block is potentially an exit point! + bind(node.tryBlock); + addAntecedent(postFinallyLabel, currentFlow); + if (node.catchClause) { + currentFlow = preTryFlow; + bind(node.catchClause); + addAntecedent(postFinallyLabel, currentFlow); + } + if (node.finallyBlock) { + currentFlow = preTryFlow; + bind(node.finallyBlock); + } + currentFlow = finishFlow(postFinallyLabel); } - function bindCaseBlock(n: CaseBlock): void { - const startState = currentReachabilityState; + function bindSwitchStatement(node: SwitchStatement): void { + const postSwitchLabel = createFlowLabel(); + bind(node.expression); + const saveBreakTarget = breakTarget; + const savePreSwitchCaseFlow = preSwitchCaseFlow; + breakTarget = postSwitchLabel; + preSwitchCaseFlow = currentFlow; + bind(node.caseBlock); + addAntecedent(postSwitchLabel, currentFlow); + const hasDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause); + if (!hasDefault) { + addAntecedent(postSwitchLabel, preSwitchCaseFlow); + } + breakTarget = saveBreakTarget; + preSwitchCaseFlow = savePreSwitchCaseFlow; + currentFlow = finishFlow(postSwitchLabel); + } - for (let i = 0; i < n.clauses.length; i++) { - const clause = n.clauses[i]; - currentReachabilityState = startState; - bind(clause); - if (clause.statements.length && - i !== n.clauses.length - 1 && // allow fallthrough from the last case - currentReachabilityState === Reachability.Reachable && - options.noFallthroughCasesInSwitch) { - errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch); + function bindCaseBlock(node: CaseBlock): void { + const clauses = node.clauses; + for (let i = 0; i < clauses.length; i++) { + const clause = clauses[i]; + if (clause.statements.length) { + if (currentFlow.kind === FlowKind.Unreachable) { + currentFlow = preSwitchCaseFlow; + } + else { + const preCaseLabel = createFlowLabel(); + addAntecedent(preCaseLabel, preSwitchCaseFlow); + addAntecedent(preCaseLabel, currentFlow); + currentFlow = finishFlow(preCaseLabel); + } + bind(clause); + if (currentFlow.kind !== FlowKind.Unreachable && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) { + errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch); + } + } + else { + bind(clause); } } } - function bindLabeledStatement(n: LabeledStatement): void { - // call bind on label (don't affect reachability) - bind(n.label); + function pushActiveLabel(name: string, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel { + const activeLabel = { + name, + breakTarget, + continueTarget, + referenced: false + }; + (activeLabels || (activeLabels = [])).push(activeLabel); + return activeLabel; + } - const ok = pushNamedLabel(n.label); - bind(n.statement); - if (ok) { - popNamedLabel(n.label, currentReachabilityState); + function popActiveLabel() { + activeLabels.pop(); + } + + function bindLabeledStatement(node: LabeledStatement): void { + const preStatementLabel = createFlowLabel(); + const postStatementLabel = createFlowLabel(); + bind(node.label); + addAntecedent(preStatementLabel, currentFlow); + const activeLabel = pushActiveLabel(node.label.text, postStatementLabel, preStatementLabel); + bind(node.statement); + popActiveLabel(); + if (!activeLabel.referenced && !options.allowUnusedLabels) { + file.bindDiagnostics.push(createDiagnosticForNode(node.label, Diagnostics.Unused_label)); + } + addAntecedent(postStatementLabel, currentFlow); + currentFlow = finishFlow(postStatementLabel); + } + + function bindBinaryExpressionFlow(node: BinaryExpression) { + const operator = node.operatorToken.kind; + if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) { + const postExpressionLabel = createFlowLabel(); + bind(node.left); + bind(node.operatorToken); + addAntecedent(postExpressionLabel, currentFlow); + currentFlow = createFlowCondition(currentFlow, node.left, /*assumeTrue*/ operator === SyntaxKind.AmpersandAmpersandToken); + bind(node.right); + addAntecedent(postExpressionLabel, currentFlow); + currentFlow = finishFlow(postExpressionLabel); + } + else { + forEachChild(node, bind); + if (operator === SyntaxKind.EqualsToken) { + currentFlow = createFlowAssignment(currentFlow, node); + } + } + } + + function bindConditionalExpressionFlow(node: ConditionalExpression) { + const postExpressionLabel = createFlowLabel(); + bind(node.condition); + const postConditionFlow = currentFlow; + currentFlow = createFlowCondition(currentFlow, node.condition, /*assumeTrue*/ true); + bind(node.whenTrue); + addAntecedent(postExpressionLabel, currentFlow); + currentFlow = createFlowCondition(postConditionFlow, node.condition, /*assumeTrue*/ false); + bind(node.whenFalse); + addAntecedent(postExpressionLabel, currentFlow); + currentFlow = finishFlow(postExpressionLabel); + } + + function bindVariableDeclarationFlow(node: VariableDeclaration) { + forEachChild(node, bind); + if (node.initializer) { + currentFlow = createFlowAssignment(currentFlow, node); } } @@ -1239,7 +1445,16 @@ namespace ts { switch (node.kind) { /* Strict mode checks */ case SyntaxKind.Identifier: + case SyntaxKind.ThisKeyword: + if (currentFlow && (isExpression(node) || parent.kind === SyntaxKind.ShorthandPropertyAssignment)) { + node.flowNode = currentFlow; + } return checkStrictModeIdentifier(node); + case SyntaxKind.PropertyAccessExpression: + if (currentFlow && isNarrowableReference(node)) { + node.flowNode = currentFlow; + } + break; case SyntaxKind.BinaryExpression: if (isInJavaScriptFile(node)) { const specialKind = getSpecialPropertyAssignmentKind(node); @@ -1663,132 +1878,53 @@ namespace ts { // reachability checks - function pushNamedLabel(name: Identifier): boolean { - initializeReachabilityStateIfNecessary(); - - if (hasProperty(labelIndexMap, name.text)) { - return false; - } - labelIndexMap[name.text] = labelStack.push(Reachability.Uninitialized) - 1; - return true; - } - - function pushImplicitLabel(): number { - initializeReachabilityStateIfNecessary(); - - const index = labelStack.push(Reachability.Uninitialized) - 1; - implicitLabels.push(index); - return index; - } - - function popNamedLabel(label: Identifier, outerState: Reachability): void { - const index = labelIndexMap[label.text]; - Debug.assert(index !== undefined); - Debug.assert(labelStack.length == index + 1); - - labelIndexMap[label.text] = undefined; - - setCurrentStateAtLabel(labelStack.pop(), outerState, label); - } - - function popImplicitLabel(implicitLabelIndex: number, outerState: Reachability): void { - if (labelStack.length !== implicitLabelIndex + 1) { - Debug.assert(false, `Label stack: ${labelStack.length}, index:${implicitLabelIndex}`); - } - - const i = implicitLabels.pop(); - - if (implicitLabelIndex !== i) { - Debug.assert(false, `i: ${i}, index: ${implicitLabelIndex}`); - } - - setCurrentStateAtLabel(labelStack.pop(), outerState, /*name*/ undefined); - } - - function setCurrentStateAtLabel(innerMergedState: Reachability, outerState: Reachability, label: Identifier): void { - if (innerMergedState === Reachability.Uninitialized) { - if (label && !options.allowUnusedLabels) { - file.bindDiagnostics.push(createDiagnosticForNode(label, Diagnostics.Unused_label)); - } - currentReachabilityState = outerState; - } - else { - currentReachabilityState = or(innerMergedState, outerState); - } - } - - function jumpToLabel(label: Identifier, outerState: Reachability): boolean { - initializeReachabilityStateIfNecessary(); - - const index = label ? labelIndexMap[label.text] : lastOrUndefined(implicitLabels); - if (index === undefined) { - // reference to unknown label or - // break/continue used outside of loops - return false; - } - const stateAtLabel = labelStack[index]; - labelStack[index] = stateAtLabel === Reachability.Uninitialized ? outerState : or(stateAtLabel, outerState); - return true; + function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { + const instanceState = getModuleInstanceState(node); + return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && options.preserveConstEnums); } function checkUnreachable(node: Node): boolean { - switch (currentReachabilityState) { - case Reachability.Unreachable: - const reportError = - // report error on all statements except empty ones - (isStatement(node) && node.kind !== SyntaxKind.EmptyStatement) || - // report error on class declarations - node.kind === SyntaxKind.ClassDeclaration || - // report error on instantiated modules or const-enums only modules if preserveConstEnums is set - (node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(node)) || - // report error on regular enums and const enums if preserveConstEnums is set - (node.kind === SyntaxKind.EnumDeclaration && (!isConstEnumDeclaration(node) || options.preserveConstEnums)); + if (currentFlow.kind !== FlowKind.Unreachable) { + return false; + } + if (currentFlow === unreachableFlow) { + const reportError = + // report error on all statements except empty ones + (isStatement(node) && node.kind !== SyntaxKind.EmptyStatement) || + // report error on class declarations + node.kind === SyntaxKind.ClassDeclaration || + // report error on instantiated modules or const-enums only modules if preserveConstEnums is set + (node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(node)) || + // report error on regular enums and const enums if preserveConstEnums is set + (node.kind === SyntaxKind.EnumDeclaration && (!isConstEnumDeclaration(node) || options.preserveConstEnums)); - if (reportError) { - currentReachabilityState = Reachability.ReportedUnreachable; + if (reportError) { + currentFlow = reportedUncreachableFlow; - // 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 reportUnreachableCode = - !options.allowUnreachableCode && - !isInAmbientContext(node) && - ( - node.kind !== SyntaxKind.VariableStatement || - getCombinedNodeFlags((node).declarationList) & NodeFlags.BlockScoped || - forEach((node).declarationList.declarations, d => d.initializer) - ); + // 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 reportUnreachableCode = + !options.allowUnreachableCode && + !isInAmbientContext(node) && + ( + node.kind !== SyntaxKind.VariableStatement || + getCombinedNodeFlags((node).declarationList) & NodeFlags.BlockScoped || + forEach((node).declarationList.declarations, d => d.initializer) + ); - if (reportUnreachableCode) { - errorOnFirstToken(node, Diagnostics.Unreachable_code_detected); - } + if (reportUnreachableCode) { + errorOnFirstToken(node, Diagnostics.Unreachable_code_detected); } - case Reachability.ReportedUnreachable: - return true; - default: - return false; + } } - - function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { - const instanceState = getModuleInstanceState(node); - return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && options.preserveConstEnums); - } - } - - function initializeReachabilityStateIfNecessary(): void { - if (labelIndexMap) { - return; - } - currentReachabilityState = Reachability.Reachable; - labelIndexMap = {}; - labelStack = []; - implicitLabels = []; + return true; } } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 92c5065b7dd..da5cc90caa4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5,6 +5,7 @@ namespace ts { let nextSymbolId = 1; let nextNodeId = 1; let nextMergeId = 1; + let nextFlowId = 1; export function getNodeId(node: Node): number { if (!node.id) { @@ -118,6 +119,7 @@ namespace ts { const nullType = createIntrinsicType(TypeFlags.Null | nullableWideningFlags, "null"); const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined"); const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); + const resolvingFlowType = createIntrinsicType(TypeFlags.Void, "__resolving__"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const emptyUnionType = emptyObjectType; @@ -186,6 +188,7 @@ namespace ts { const mergedSymbols: Symbol[] = []; const symbolLinks: SymbolLinks[] = []; const nodeLinks: NodeLinks[] = []; + const flowTypeCaches: Map[] = []; const potentialThisCollisions: Node[] = []; const awaitedTypeStack: number[] = []; @@ -7136,11 +7139,11 @@ namespace ts { Debug.fail("should not get here"); } - // Return the assignment key for a "dotted name" (i.e. a sequence of identifiers + // Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers // separated by dots). The key consists of the id of the symbol referenced by the // leftmost identifier followed by zero or more property names separated by dots. // The result is undefined if the reference isn't a dotted name. - function getAssignmentKey(node: Node): string { + function getFlowCacheKey(node: Node): string { if (node.kind === SyntaxKind.Identifier) { const symbol = getResolvedSymbol(node); return symbol !== unknownSymbol ? "" + getSymbolId(symbol) : undefined; @@ -7149,125 +7152,12 @@ namespace ts { return "0"; } if (node.kind === SyntaxKind.PropertyAccessExpression) { - const key = getAssignmentKey((node).expression); + const key = getFlowCacheKey((node).expression); return key && key + "." + (node).name.text; } return undefined; } - function hasInitializer(node: VariableLikeDeclaration): boolean { - return !!(node.initializer || isBindingPattern(node.parent) && hasInitializer(node.parent.parent)); - } - - // For a given node compute a map of which dotted names are assigned within - // the node. - function getAssignmentMap(node: Node): Map { - const assignmentMap: Map = {}; - visit(node); - return assignmentMap; - - function visitReference(node: Identifier | PropertyAccessExpression) { - if (isAssignmentTarget(node) || isCompoundAssignmentTarget(node)) { - const key = getAssignmentKey(node); - if (key) { - assignmentMap[key] = true; - } - } - forEachChild(node, visit); - } - - function visitVariableDeclaration(node: VariableLikeDeclaration) { - if (!isBindingPattern(node.name) && hasInitializer(node)) { - assignmentMap[getSymbolId(getSymbolOfNode(node))] = true; - } - forEachChild(node, visit); - } - - function visit(node: Node) { - switch (node.kind) { - case SyntaxKind.Identifier: - case SyntaxKind.PropertyAccessExpression: - visitReference(node); - break; - case SyntaxKind.VariableDeclaration: - case SyntaxKind.BindingElement: - visitVariableDeclaration(node); - break; - case SyntaxKind.BinaryExpression: - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - case SyntaxKind.ArrayLiteralExpression: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - case SyntaxKind.TypeAssertionExpression: - case SyntaxKind.AsExpression: - case SyntaxKind.NonNullExpression: - case SyntaxKind.ParenthesizedExpression: - case SyntaxKind.PrefixUnaryExpression: - case SyntaxKind.DeleteExpression: - case SyntaxKind.AwaitExpression: - case SyntaxKind.TypeOfExpression: - case SyntaxKind.VoidExpression: - case SyntaxKind.PostfixUnaryExpression: - case SyntaxKind.YieldExpression: - case SyntaxKind.ConditionalExpression: - case SyntaxKind.SpreadElementExpression: - case SyntaxKind.Block: - case SyntaxKind.VariableStatement: - case SyntaxKind.ExpressionStatement: - case SyntaxKind.IfStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - case SyntaxKind.ReturnStatement: - case SyntaxKind.WithStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.CaseBlock: - case SyntaxKind.CaseClause: - case SyntaxKind.DefaultClause: - case SyntaxKind.LabeledStatement: - case SyntaxKind.ThrowStatement: - case SyntaxKind.TryStatement: - case SyntaxKind.CatchClause: - case SyntaxKind.JsxElement: - case SyntaxKind.JsxSelfClosingElement: - case SyntaxKind.JsxAttribute: - case SyntaxKind.JsxSpreadAttribute: - case SyntaxKind.JsxOpeningElement: - case SyntaxKind.JsxExpression: - forEachChild(node, visit); - break; - } - } - } - - function isReferenceAssignedWithin(reference: Node, node: Node): boolean { - if (reference.kind !== SyntaxKind.ThisKeyword) { - const key = getAssignmentKey(reference); - if (key) { - const links = getNodeLinks(node); - return (links.assignmentMap || (links.assignmentMap = getAssignmentMap(node)))[key]; - } - } - return false; - } - - function isAnyPartOfReferenceAssignedWithin(reference: Node, node: Node) { - while (true) { - if (isReferenceAssignedWithin(reference, node)) { - return true; - } - if (reference.kind !== SyntaxKind.PropertyAccessExpression) { - return false; - } - reference = (reference).expression; - } - } - function isNullOrUndefinedLiteral(node: Expression) { return node.kind === SyntaxKind.NullKeyword || node.kind === SyntaxKind.Identifier && getResolvedSymbol(node) === undefinedSymbol; @@ -7299,16 +7189,68 @@ namespace ts { return false; } - // Get the narrowed type of a given symbol at a given location + function containsMatchingReference(source: Node, target: Node) { + while (true) { + if (isMatchingReference(source, target)) { + return true; + } + if (source.kind !== SyntaxKind.PropertyAccessExpression) { + return false; + } + source = (source).expression; + } + } + + function hasMatchingArgument(callExpression: CallExpression, target: Node) { + if (callExpression.arguments) { + for (const argument of callExpression.arguments) { + if (isMatchingReference(argument, target)) { + return true; + } + } + } + if (callExpression.expression.kind === SyntaxKind.PropertyAccessExpression && + isMatchingReference((callExpression.expression).expression, target)) { + return true; + } + return false; + } + + function getFlowTypeCache(flow: FlowNode): Map { + if (!flow.id) { + flow.id = nextFlowId; + nextFlowId++; + } + return flowTypeCaches[flow.id] || (flowTypeCaches[flow.id] = {}); + } + + function isNarrowableReference(expr: Node): boolean { + return expr.kind === SyntaxKind.Identifier || + expr.kind === SyntaxKind.ThisKeyword || + expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((expr).expression); + } + + function getAssignmentReducedType(type: Type, assignedType: Type) { + if (type.flags & TypeFlags.Union) { + const reducedTypes = filter((type).types, t => isTypeAssignableTo(assignedType, t)); + if (reducedTypes.length) { + return reducedTypes.length === 1 ? reducedTypes[0] : getUnionType(reducedTypes); + } + } + return type; + } + function getNarrowedTypeOfReference(type: Type, reference: Node) { if (!(type.flags & (TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter))) { return type; } + if (!isNarrowableReference(reference)) { + return type; + } const leftmostNode = getLeftmostIdentifierOrThis(reference); if (!leftmostNode) { return type; } - let top: Node; if (leftmostNode.kind === SyntaxKind.Identifier) { const leftmostSymbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(leftmostNode)); if (!leftmostSymbol) { @@ -7318,74 +7260,138 @@ namespace ts { if (!declaration || declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.Parameter && declaration.kind !== SyntaxKind.BindingElement) { return type; } - top = getDeclarationContainer(declaration); - } - const originalType = type; - const nodeStack: { node: Node, child: Node }[] = []; - let node: Node = reference; - loop: while (node.parent) { - const child = node; - node = node.parent; - switch (node.kind) { - case SyntaxKind.IfStatement: - case SyntaxKind.ConditionalExpression: - case SyntaxKind.BinaryExpression: - nodeStack.push({node, child}); - break; - case SyntaxKind.SourceFile: - case SyntaxKind.ModuleDeclaration: - break loop; - default: - if (node === top || isFunctionLikeKind(node.kind)) { - break loop; - } - break; - } } + return getFlowTypeOfReference(reference, type, type); + } - let nodes: { node: Node, child: Node }; - while (nodes = nodeStack.pop()) { - const {node, child} = nodes; - switch (node.kind) { - case SyntaxKind.IfStatement: - // In a branch of an if statement, narrow based on controlling expression - if (child !== (node).expression) { - type = narrowType(type, (node).expression, /*assumeTrue*/ child === (node).thenStatement); - } - break; - case SyntaxKind.ConditionalExpression: - // In a branch of a conditional expression, narrow based on controlling condition - if (child !== (node).condition) { - type = narrowType(type, (node).condition, /*assumeTrue*/ child === (node).whenTrue); - } - break; - case SyntaxKind.BinaryExpression: - // In the right operand of an && or ||, narrow based on left operand - if (child === (node).right) { - if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { - type = narrowType(type, (node).left, /*assumeTrue*/ true); + function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) { + let key: string; + return reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : initialType; + + function getTypeAtFlowNode(flow: FlowNode): Type { + while (true) { + switch (flow.kind) { + case FlowKind.Assignment: + const type = getTypeAtFlowAssignment(flow); + if (!type) { + flow = (flow).antecedent; + continue; } - else if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { - type = narrowType(type, (node).left, /*assumeTrue*/ false); + return type; + case FlowKind.Condition: + return getTypeAtFlowCondition(flow); + case FlowKind.Label: + if ((flow).antecedents.length === 1) { + flow = (flow).antecedents[0]; + continue; } + return getTypeAtFlowLabel(flow); + } + // At the top of the flow we have the initial type + return initialType; + } + } + + function getTypeAtVariableDeclaration(node: VariableDeclaration) { + if (reference.kind === SyntaxKind.Identifier && !isBindingPattern(node.name) && getResolvedSymbol(reference) === getSymbolOfNode(node)) { + return getAssignmentReducedType(declaredType, checkExpressionCached((node).initializer)); + } + return undefined; + } + + function getTypeAtForInOrForOfStatement(node: ForInStatement | ForOfStatement) { + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + if (reference.kind === SyntaxKind.Identifier) { + const variable = (node.initializer).declarations[0]; + if (variable && !isBindingPattern(variable.name) && getResolvedSymbol(reference) === getSymbolOfNode(variable)) { + return declaredType; + } + } + } + else { + if (isMatchingReference(reference, node.initializer)) { + const type = node.kind === SyntaxKind.ForOfStatement ? checkRightHandSideOfForOf(node.expression) : stringType; + return getAssignmentReducedType(declaredType, type); + } + if (reference.kind === SyntaxKind.PropertyAccessExpression && + containsMatchingReference((reference).expression, node.initializer)) { + return declaredType; + } + } + return undefined; + } + + function getTypeAtFlowAssignment(flow: FlowAssignment) { + const node = flow.node; + switch (node.kind) { + case SyntaxKind.BinaryExpression: + // If reference matches left hand side and type on right is properly assignable, + // return type on right. Otherwise default to the declared type. + if (isMatchingReference(reference, (node).left)) { + return getAssignmentReducedType(declaredType, checkExpressionCached((node).right)); + } + // We didn't have a direct match. However, if the reference is a dotted name, this + // may be an assignment to a left hand part of the reference. For example, for a + // reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case, + // return the declared type. + if (reference.kind === SyntaxKind.PropertyAccessExpression && + containsMatchingReference((reference).expression, (node).left)) { + return declaredType; } break; - default: - Debug.fail("Unreachable!"); - } - - // Use original type if construct contains assignments to variable - if (type !== originalType && isAnyPartOfReferenceAssignedWithin(reference, node)) { - type = originalType; + case SyntaxKind.VariableDeclaration: + return getTypeAtVariableDeclaration(node); + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + return getTypeAtForInOrForOfStatement(node); } + // Assignment doesn't affect reference + return undefined; } - // Preserve old top-level behavior - if the branch is really an empty set, revert to prior type - if (type === emptyUnionType) { - type = originalType; + function getTypeAtFlowCondition(flow: FlowCondition) { + const type = getTypeAtFlowNode(flow.antecedent); + if (type === resolvingFlowType) { + return type; + } + return narrowType(type, (flow).expression, (flow).assumeTrue); } - return type; + function getTypeAtFlowNodeCached(flow: FlowNode) { + const cache = getFlowTypeCache(flow); + if (!key) { + key = getFlowCacheKey(reference); + } + let type = cache[key]; + if (type) { + return type; + } + cache[key] = resolvingFlowType; + type = getTypeAtFlowNode(flow); + cache[key] = type !== resolvingFlowType ? type : undefined; + return type; + } + + function getTypeAtFlowLabel(flow: FlowLabel) { + const antecedentTypes: Type[] = []; + for (const antecedent of flow.antecedents) { + const t = getTypeAtFlowNodeCached(antecedent); + if (t !== resolvingFlowType) { + // If the type at a particular antecedent path is the declared type, there is no + // reason to process more antecedents since the only possible outcome is subtypes + // that are be removed in the final union type anyway. + if (t === declaredType) { + return t; + } + if (!contains(antecedentTypes, t)) { + antecedentTypes.push(t); + } + } + } + return antecedentTypes.length === 0 ? declaredType : + antecedentTypes.length === 1 ? antecedentTypes[0] : + getUnionType(antecedentTypes); + } function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { return strictNullChecks && assumeTrue && isMatchingReference(expr, reference) ? getNonNullableType(type) : type; @@ -7574,7 +7580,7 @@ namespace ts { } function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { - if (type.flags & TypeFlags.Any) { + if (type.flags & TypeFlags.Any || !hasMatchingArgument(callExpression, reference)) { return type; } const signature = getResolvedSignature(callExpression); @@ -7656,98 +7662,6 @@ namespace ts { return expression; } - function findFirstAssignment(symbol: Symbol, container: Node): Node { - return visit(isFunctionLike(container) ? (container).body : container); - - function visit(node: Node): Node { - switch (node.kind) { - case SyntaxKind.Identifier: - const assignment = getAssignmentRoot(node); - return assignment && getResolvedSymbol(node) === symbol ? assignment : undefined; - case SyntaxKind.BinaryExpression: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.BindingElement: - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - case SyntaxKind.ArrayLiteralExpression: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.PropertyAccessExpression: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - case SyntaxKind.TypeAssertionExpression: - case SyntaxKind.AsExpression: - case SyntaxKind.NonNullExpression: - case SyntaxKind.ParenthesizedExpression: - case SyntaxKind.PrefixUnaryExpression: - case SyntaxKind.DeleteExpression: - case SyntaxKind.AwaitExpression: - case SyntaxKind.TypeOfExpression: - case SyntaxKind.VoidExpression: - case SyntaxKind.PostfixUnaryExpression: - case SyntaxKind.YieldExpression: - case SyntaxKind.ConditionalExpression: - case SyntaxKind.SpreadElementExpression: - case SyntaxKind.VariableStatement: - case SyntaxKind.ExpressionStatement: - case SyntaxKind.IfStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - case SyntaxKind.ReturnStatement: - case SyntaxKind.WithStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.CaseBlock: - case SyntaxKind.CaseClause: - case SyntaxKind.DefaultClause: - case SyntaxKind.LabeledStatement: - case SyntaxKind.ThrowStatement: - case SyntaxKind.TryStatement: - case SyntaxKind.CatchClause: - case SyntaxKind.JsxElement: - case SyntaxKind.JsxSelfClosingElement: - case SyntaxKind.JsxAttribute: - case SyntaxKind.JsxSpreadAttribute: - case SyntaxKind.JsxOpeningElement: - case SyntaxKind.JsxExpression: - case SyntaxKind.Block: - case SyntaxKind.SourceFile: - return forEachChild(node, visit); - } - return undefined; - } - } - - function checkVariableAssignedBefore(symbol: Symbol, reference: Node) { - if (!(symbol.flags & SymbolFlags.Variable)) { - return; - } - const declaration = symbol.valueDeclaration; - if (!declaration || declaration.kind !== SyntaxKind.VariableDeclaration || (declaration).initializer) { - return; - } - const parentParentKind = declaration.parent.parent.kind; - if (parentParentKind === SyntaxKind.ForOfStatement || parentParentKind === SyntaxKind.ForInStatement) { - return; - } - const declarationContainer = getContainingFunction(declaration) || getSourceFileOfNode(declaration); - const referenceContainer = getContainingFunction(reference) || getSourceFileOfNode(reference); - if (declarationContainer !== referenceContainer) { - return; - } - const links = getSymbolLinks(symbol); - if (!links.firstAssignmentChecked) { - links.firstAssignmentChecked = true; - links.firstAssignment = findFirstAssignment(symbol, declarationContainer); - } - if (links.firstAssignment && links.firstAssignment.end <= reference.pos) { - return; - } - error(reference, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); - } - function checkIdentifier(node: Identifier): Type { const symbol = getResolvedSymbol(node); @@ -7800,10 +7714,18 @@ namespace ts { checkNestedBlockScopedBinding(node, symbol); const type = getTypeOfSymbol(localOrExportSymbol); - if (strictNullChecks && !isAssignmentTarget(node) && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined)) { - checkVariableAssignedBefore(symbol, node); + if (!(localOrExportSymbol.flags & SymbolFlags.Variable) || isAssignmentTarget(node)) { + return type; } - return getNarrowedTypeOfReference(type, node); + const declaration = localOrExportSymbol.valueDeclaration; + const defaultsToDeclaredType = !strictNullChecks || !declaration || + declaration.kind === SyntaxKind.Parameter || isInAmbientContext(declaration) || + getContainingFunction(declaration) !== getContainingFunction(node); + const flowType = getFlowTypeOfReference(node, type, defaultsToDeclaredType ? type : undefinedType); + if (strictNullChecks && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) { + error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); + } + return flowType; } function isInsideFunction(node: Node, threshold: Node): boolean { @@ -8715,8 +8637,10 @@ namespace ts { return mapper && mapper.context; } - // Return the root assignment node of an assignment target - function getAssignmentRoot(node: Node): Node { + // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property + // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is + // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'. + function isAssignmentTarget(node: Node): boolean { while (node.parent.kind === SyntaxKind.ParenthesizedExpression) { node = node.parent; } @@ -8734,23 +8658,7 @@ namespace ts { const parent = node.parent; return parent.kind === SyntaxKind.BinaryExpression && (parent).operatorToken.kind === SyntaxKind.EqualsToken && - (parent).left === node ? parent : undefined; - } - - // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property - // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is - // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'. - function isAssignmentTarget(node: Node): boolean { - return !!getAssignmentRoot(node); - } - - function isCompoundAssignmentTarget(node: Node) { - const parent = node.parent; - if (parent.kind === SyntaxKind.BinaryExpression && (parent).left === node) { - const operator = (parent).operatorToken.kind; - return operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment; - } - return false; + (parent).left === node; } function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type { @@ -9604,7 +9512,7 @@ namespace ts { } const propType = getTypeOfSymbol(prop); - return node.kind === SyntaxKind.PropertyAccessExpression && prop.flags & SymbolFlags.Property ? + return node.kind === SyntaxKind.PropertyAccessExpression && prop.flags & SymbolFlags.Property && !isAssignmentTarget(node) ? getNarrowedTypeOfReference(propType, node) : propType; } @@ -16177,7 +16085,7 @@ namespace ts { } if (entityName.parent.kind === SyntaxKind.ExportAssignment) { - return resolveEntityName(entityName, + return resolveEntityName(entityName, /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 546d1631945..c850fe47012 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -449,6 +449,7 @@ namespace ts { /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) /* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding) /* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes) + /* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding) } export interface NodeArray extends Array, TextRange { @@ -1518,6 +1519,39 @@ namespace ts { isBracketed: boolean; } + export const enum FlowKind { + Unreachable, + Start, + Label, + Assignment, + Condition + } + + export interface FlowNode { + kind: FlowKind; // Node kind + id?: number; // Node id used by flow type cache in checker + } + + // FlowLabel represents a junction with multiple possible preceding control flows. + export interface FlowLabel extends FlowNode { + antecedents: FlowNode[]; + } + + // FlowAssignment represents a node that possibly assigns a value to one or more + // references. + export interface FlowAssignment extends FlowNode { + node: BinaryExpression | VariableDeclaration | ForInStatement | ForOfStatement; + antecedent: FlowNode; + } + + // FlowCondition represents a condition that is known to be true or false at the + // node's location in the control flow. + export interface FlowCondition extends FlowNode { + expression: Expression; + assumeTrue: boolean; + antecedent: FlowNode; + } + export interface AmdDependency { path: string; name: string; From afa1714c034f5d51c2151457cbf20d20ba239e84 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Mar 2016 10:22:08 -0700 Subject: [PATCH 006/110] Add type annotations to suppress circularity errors --- src/compiler/parser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b7c011631ee..3bbb86b58e0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1811,7 +1811,7 @@ namespace ts { function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { let entity: EntityName = parseIdentifier(diagnosticMessage); while (parseOptional(SyntaxKind.DotToken)) { - const node = createNode(SyntaxKind.QualifiedName, entity.pos); + const node: QualifiedName = createNode(SyntaxKind.QualifiedName, entity.pos); // !!! node.left = entity; node.right = parseRightSideOfDot(allowReservedWords); entity = finishNode(node); @@ -3639,7 +3639,7 @@ namespace ts { let elementName: EntityName = parseIdentifierName(); while (parseOptional(SyntaxKind.DotToken)) { scanJsxIdentifier(); - const node = createNode(SyntaxKind.QualifiedName, elementName.pos); + const node: QualifiedName = createNode(SyntaxKind.QualifiedName, elementName.pos); // !!! node.left = elementName; node.right = parseIdentifierName(); elementName = finishNode(node); From 7c45c7ba9f211e382da31793f9c2e7ea4e5a43fa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Mar 2016 10:50:06 -0700 Subject: [PATCH 007/110] Fixing tests --- .../stringLiteralTypesInUnionTypes01.js | 8 ++-- .../stringLiteralTypesInUnionTypes01.symbols | 6 ++- .../stringLiteralTypesInUnionTypes01.types | 8 ++-- .../stringLiteralTypesInUnionTypes02.js | 8 ++-- .../stringLiteralTypesInUnionTypes02.symbols | 6 ++- .../stringLiteralTypesInUnionTypes02.types | 46 +++++++++---------- .../stringLiteralTypesInUnionTypes03.js | 4 +- .../stringLiteralTypesInUnionTypes03.symbols | 3 +- .../stringLiteralTypesInUnionTypes03.types | 4 +- .../stringLiteralTypesInUnionTypes04.js | 8 ++-- .../stringLiteralTypesInUnionTypes04.symbols | 6 ++- .../stringLiteralTypesInUnionTypes04.types | 8 ++-- .../stringLiteralTypesTypePredicates01.js | 4 +- ...stringLiteralTypesTypePredicates01.symbols | 3 +- .../stringLiteralTypesTypePredicates01.types | 4 +- .../stringLiteralTypesInUnionTypes01.ts | 4 +- .../stringLiteralTypesInUnionTypes02.ts | 4 +- .../stringLiteralTypesInUnionTypes03.ts | 2 +- .../stringLiteralTypesInUnionTypes04.ts | 4 +- .../stringLiteralTypesTypePredicates01.ts | 2 +- 20 files changed, 75 insertions(+), 67 deletions(-) diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes01.js b/tests/baselines/reference/stringLiteralTypesInUnionTypes01.js index d970310d68e..bdf06d393aa 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes01.js +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes01.js @@ -2,8 +2,8 @@ type T = "foo" | "bar" | "baz"; -var x: "foo" | "bar" | "baz" = "foo"; -var y: T = "bar"; +var x: "foo" | "bar" | "baz" = undefined; +var y: T = undefined; if (x === "foo") { let a = x; @@ -21,8 +21,8 @@ x = y; y = x; //// [stringLiteralTypesInUnionTypes01.js] -var x = "foo"; -var y = "bar"; +var x = undefined; +var y = undefined; if (x === "foo") { var a = x; } diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes01.symbols b/tests/baselines/reference/stringLiteralTypesInUnionTypes01.symbols index c608929383e..15a8db13cd0 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes01.symbols +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes01.symbols @@ -3,12 +3,14 @@ type T = "foo" | "bar" | "baz"; >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes01.ts, 0, 0)) -var x: "foo" | "bar" | "baz" = "foo"; +var x: "foo" | "bar" | "baz" = undefined; >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes01.ts, 3, 3)) +>undefined : Symbol(undefined) -var y: T = "bar"; +var y: T = undefined; >y : Symbol(y, Decl(stringLiteralTypesInUnionTypes01.ts, 4, 3)) >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes01.ts, 0, 0)) +>undefined : Symbol(undefined) if (x === "foo") { >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes01.ts, 3, 3)) diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes01.types b/tests/baselines/reference/stringLiteralTypesInUnionTypes01.types index e5ff509822b..7201aaa91ca 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes01.types +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes01.types @@ -3,14 +3,14 @@ type T = "foo" | "bar" | "baz"; >T : "foo" | "bar" | "baz" -var x: "foo" | "bar" | "baz" = "foo"; +var x: "foo" | "bar" | "baz" = undefined; >x : "foo" | "bar" | "baz" ->"foo" : "foo" +>undefined : undefined -var y: T = "bar"; +var y: T = undefined; >y : "foo" | "bar" | "baz" >T : "foo" | "bar" | "baz" ->"bar" : "bar" +>undefined : undefined if (x === "foo") { >x === "foo" : boolean diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.js b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.js index 19b9c837c9d..bca25e744c9 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.js +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.js @@ -2,8 +2,8 @@ type T = string | "foo" | "bar" | "baz"; -var x: "foo" | "bar" | "baz" | string = "foo"; -var y: T = "bar"; +var x: "foo" | "bar" | "baz" | string = undefined; +var y: T = undefined; if (x === "foo") { let a = x; @@ -21,8 +21,8 @@ x = y; y = x; //// [stringLiteralTypesInUnionTypes02.js] -var x = "foo"; -var y = "bar"; +var x = undefined; +var y = undefined; if (x === "foo") { var a = x; } diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.symbols b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.symbols index c9b31dc710a..c35b7a0691b 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.symbols +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.symbols @@ -3,12 +3,14 @@ type T = string | "foo" | "bar" | "baz"; >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes02.ts, 0, 0)) -var x: "foo" | "bar" | "baz" | string = "foo"; +var x: "foo" | "bar" | "baz" | string = undefined; >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes02.ts, 3, 3)) +>undefined : Symbol(undefined) -var y: T = "bar"; +var y: T = undefined; >y : Symbol(y, Decl(stringLiteralTypesInUnionTypes02.ts, 4, 3)) >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes02.ts, 0, 0)) +>undefined : Symbol(undefined) if (x === "foo") { >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes02.ts, 3, 3)) diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types index b468c620376..242248617e0 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types @@ -3,60 +3,60 @@ type T = string | "foo" | "bar" | "baz"; >T : string | "foo" | "bar" | "baz" -var x: "foo" | "bar" | "baz" | string = "foo"; +var x: "foo" | "bar" | "baz" | string = undefined; >x : "foo" | "bar" | "baz" | string ->"foo" : "foo" +>undefined : undefined -var y: T = "bar"; +var y: T = undefined; >y : string | "foo" | "bar" | "baz" >T : string | "foo" | "bar" | "baz" ->"bar" : "bar" +>undefined : undefined if (x === "foo") { >x === "foo" : boolean ->x : "foo" | "bar" | "baz" | string +>x : string >"foo" : string let a = x; ->a : "foo" | "bar" | "baz" | string ->x : "foo" | "bar" | "baz" | string +>a : string +>x : string } else if (x !== "bar") { >x !== "bar" : boolean ->x : "foo" | "bar" | "baz" | string +>x : string >"bar" : string let b = x || y; >b : string >x || y : string ->x : "foo" | "bar" | "baz" | string ->y : string | "foo" | "bar" | "baz" +>x : string +>y : string } else { let c = x; ->c : "foo" | "bar" | "baz" | string ->x : "foo" | "bar" | "baz" | string +>c : string +>x : string let d = y; ->d : string | "foo" | "bar" | "baz" ->y : string | "foo" | "bar" | "baz" +>d : string +>y : string let e: (typeof x) | (typeof y) = c || d; ->e : "foo" | "bar" | "baz" | string ->x : "foo" | "bar" | "baz" | string ->y : string | "foo" | "bar" | "baz" +>e : string +>x : string +>y : string >c || d : string ->c : "foo" | "bar" | "baz" | string ->d : string | "foo" | "bar" | "baz" +>c : string +>d : string } x = y; ->x = y : string | "foo" | "bar" | "baz" +>x = y : string >x : "foo" | "bar" | "baz" | string ->y : string | "foo" | "bar" | "baz" +>y : string y = x; ->y = x : "foo" | "bar" | "baz" | string +>y = x : string >y : string | "foo" | "bar" | "baz" ->x : "foo" | "bar" | "baz" | string +>x : string diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes03.js b/tests/baselines/reference/stringLiteralTypesInUnionTypes03.js index f6728e0b2fb..6264c99c13d 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes03.js +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes03.js @@ -3,7 +3,7 @@ type T = number | "foo" | "bar"; var x: "foo" | "bar" | number; -var y: T = "bar"; +var y: T = undefined; if (x === "foo") { let a = x; @@ -22,7 +22,7 @@ y = x; //// [stringLiteralTypesInUnionTypes03.js] var x; -var y = "bar"; +var y = undefined; if (x === "foo") { var a = x; } diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes03.symbols b/tests/baselines/reference/stringLiteralTypesInUnionTypes03.symbols index df5498d9a59..6d519e24225 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes03.symbols +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes03.symbols @@ -6,9 +6,10 @@ type T = number | "foo" | "bar"; var x: "foo" | "bar" | number; >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes03.ts, 3, 3)) -var y: T = "bar"; +var y: T = undefined; >y : Symbol(y, Decl(stringLiteralTypesInUnionTypes03.ts, 4, 3)) >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes03.ts, 0, 0)) +>undefined : Symbol(undefined) if (x === "foo") { >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes03.ts, 3, 3)) diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes03.types b/tests/baselines/reference/stringLiteralTypesInUnionTypes03.types index 5fca6e69be9..920f7e1a71c 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes03.types +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes03.types @@ -6,10 +6,10 @@ type T = number | "foo" | "bar"; var x: "foo" | "bar" | number; >x : "foo" | "bar" | number -var y: T = "bar"; +var y: T = undefined; >y : number | "foo" | "bar" >T : number | "foo" | "bar" ->"bar" : "bar" +>undefined : undefined if (x === "foo") { >x === "foo" : boolean diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes04.js b/tests/baselines/reference/stringLiteralTypesInUnionTypes04.js index dc6cf51ad1e..85c9a30c49d 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes04.js +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes04.js @@ -2,8 +2,8 @@ type T = "" | "foo"; -let x: T = ""; -let y: T = "foo"; +let x: T = undefined; +let y: T = undefined; if (x === "") { let a = x; @@ -38,8 +38,8 @@ if (!!!x) { } //// [stringLiteralTypesInUnionTypes04.js] -var x = ""; -var y = "foo"; +var x = undefined; +var y = undefined; if (x === "") { var a = x; } diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes04.symbols b/tests/baselines/reference/stringLiteralTypesInUnionTypes04.symbols index ced93fcefc9..9904fa8613f 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes04.symbols +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes04.symbols @@ -3,13 +3,15 @@ type T = "" | "foo"; >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes04.ts, 0, 0)) -let x: T = ""; +let x: T = undefined; >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes04.ts, 3, 3)) >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes04.ts, 0, 0)) +>undefined : Symbol(undefined) -let y: T = "foo"; +let y: T = undefined; >y : Symbol(y, Decl(stringLiteralTypesInUnionTypes04.ts, 4, 3)) >T : Symbol(T, Decl(stringLiteralTypesInUnionTypes04.ts, 0, 0)) +>undefined : Symbol(undefined) if (x === "") { >x : Symbol(x, Decl(stringLiteralTypesInUnionTypes04.ts, 3, 3)) diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes04.types b/tests/baselines/reference/stringLiteralTypesInUnionTypes04.types index ad92dc360d0..fdaaa21b6cb 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes04.types +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes04.types @@ -3,15 +3,15 @@ type T = "" | "foo"; >T : "" | "foo" -let x: T = ""; +let x: T = undefined; >x : "" | "foo" >T : "" | "foo" ->"" : "" +>undefined : undefined -let y: T = "foo"; +let y: T = undefined; >y : "" | "foo" >T : "" | "foo" ->"foo" : "foo" +>undefined : undefined if (x === "") { >x === "" : boolean diff --git a/tests/baselines/reference/stringLiteralTypesTypePredicates01.js b/tests/baselines/reference/stringLiteralTypesTypePredicates01.js index fd4129d272d..fdd03c83aa5 100644 --- a/tests/baselines/reference/stringLiteralTypesTypePredicates01.js +++ b/tests/baselines/reference/stringLiteralTypesTypePredicates01.js @@ -8,7 +8,7 @@ function kindIs(kind: Kind, is: Kind): boolean { return kind === is; } -var x: Kind = "A"; +var x: Kind = undefined; if (kindIs(x, "A")) { let a = x; @@ -28,7 +28,7 @@ else { function kindIs(kind, is) { return kind === is; } -var x = "A"; +var x = undefined; if (kindIs(x, "A")) { var a = x; } diff --git a/tests/baselines/reference/stringLiteralTypesTypePredicates01.symbols b/tests/baselines/reference/stringLiteralTypesTypePredicates01.symbols index 6b18cab7432..aea8c6ac262 100644 --- a/tests/baselines/reference/stringLiteralTypesTypePredicates01.symbols +++ b/tests/baselines/reference/stringLiteralTypesTypePredicates01.symbols @@ -29,9 +29,10 @@ function kindIs(kind: Kind, is: Kind): boolean { >is : Symbol(is, Decl(stringLiteralTypesTypePredicates01.ts, 5, 27)) } -var x: Kind = "A"; +var x: Kind = undefined; >x : Symbol(x, Decl(stringLiteralTypesTypePredicates01.ts, 9, 3)) >Kind : Symbol(Kind, Decl(stringLiteralTypesTypePredicates01.ts, 0, 0)) +>undefined : Symbol(undefined) if (kindIs(x, "A")) { >kindIs : Symbol(kindIs, Decl(stringLiteralTypesTypePredicates01.ts, 1, 21), Decl(stringLiteralTypesTypePredicates01.ts, 3, 50), Decl(stringLiteralTypesTypePredicates01.ts, 4, 50)) diff --git a/tests/baselines/reference/stringLiteralTypesTypePredicates01.types b/tests/baselines/reference/stringLiteralTypesTypePredicates01.types index 41da80afd30..4a765ea5312 100644 --- a/tests/baselines/reference/stringLiteralTypesTypePredicates01.types +++ b/tests/baselines/reference/stringLiteralTypesTypePredicates01.types @@ -30,10 +30,10 @@ function kindIs(kind: Kind, is: Kind): boolean { >is : "A" | "B" } -var x: Kind = "A"; +var x: Kind = undefined; >x : "A" | "B" >Kind : "A" | "B" ->"A" : "A" +>undefined : undefined if (kindIs(x, "A")) { >kindIs(x, "A") : boolean diff --git a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes01.ts b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes01.ts index b8ed1b47dd4..05f8c511118 100644 --- a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes01.ts +++ b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes01.ts @@ -2,8 +2,8 @@ type T = "foo" | "bar" | "baz"; -var x: "foo" | "bar" | "baz" = "foo"; -var y: T = "bar"; +var x: "foo" | "bar" | "baz" = undefined; +var y: T = undefined; if (x === "foo") { let a = x; diff --git a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes02.ts b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes02.ts index 2cc63ab4460..ee61efc37ca 100644 --- a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes02.ts +++ b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes02.ts @@ -2,8 +2,8 @@ type T = string | "foo" | "bar" | "baz"; -var x: "foo" | "bar" | "baz" | string = "foo"; -var y: T = "bar"; +var x: "foo" | "bar" | "baz" | string = undefined; +var y: T = undefined; if (x === "foo") { let a = x; diff --git a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes03.ts b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes03.ts index d5c6a38af79..96a4f035c4b 100644 --- a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes03.ts +++ b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes03.ts @@ -3,7 +3,7 @@ type T = number | "foo" | "bar"; var x: "foo" | "bar" | number; -var y: T = "bar"; +var y: T = undefined; if (x === "foo") { let a = x; diff --git a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes04.ts b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes04.ts index e9d062b0e5c..9f37e272b46 100644 --- a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes04.ts +++ b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes04.ts @@ -2,8 +2,8 @@ type T = "" | "foo"; -let x: T = ""; -let y: T = "foo"; +let x: T = undefined; +let y: T = undefined; if (x === "") { let a = x; diff --git a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesTypePredicates01.ts b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesTypePredicates01.ts index a78918c8122..2199ff3a7c7 100644 --- a/tests/cases/conformance/types/stringLiteral/stringLiteralTypesTypePredicates01.ts +++ b/tests/cases/conformance/types/stringLiteral/stringLiteralTypesTypePredicates01.ts @@ -8,7 +8,7 @@ function kindIs(kind: Kind, is: Kind): boolean { return kind === is; } -var x: Kind = "A"; +var x: Kind = undefined; if (kindIs(x, "A")) { let a = x; From 80c2e5ead2904f4293d7200e6623c94bb76f970d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 22 Mar 2016 10:57:56 -0700 Subject: [PATCH 008/110] Accepting new baselines --- .../nestedBlockScopedBindings13.errors.txt | 18 ++ .../nestedBlockScopedBindings13.symbols | 16 -- .../nestedBlockScopedBindings13.types | 23 -- .../nestedBlockScopedBindings14.errors.txt | 20 ++ .../nestedBlockScopedBindings14.symbols | 22 -- .../nestedBlockScopedBindings14.types | 29 --- .../nestedBlockScopedBindings15.errors.txt | 46 ++++ .../nestedBlockScopedBindings15.symbols | 46 ---- .../nestedBlockScopedBindings15.types | 66 ----- .../nestedBlockScopedBindings16.errors.txt | 50 ++++ .../nestedBlockScopedBindings16.symbols | 58 ----- .../nestedBlockScopedBindings16.types | 78 ------ .../nestedBlockScopedBindings5.errors.txt | 92 +++++++ .../nestedBlockScopedBindings5.symbols | 163 ------------- .../nestedBlockScopedBindings5.types | 227 ------------------ .../nestedBlockScopedBindings7.errors.txt | 16 ++ .../nestedBlockScopedBindings7.symbols | 14 -- .../nestedBlockScopedBindings7.types | 19 -- .../nestedBlockScopedBindings8.errors.txt | 18 ++ .../nestedBlockScopedBindings8.symbols | 20 -- .../nestedBlockScopedBindings8.types | 25 -- .../parser_duplicateLabel1.errors.txt | 5 +- .../parser_duplicateLabel2.errors.txt | 5 +- .../reference/reachabilityChecks5.errors.txt | 5 +- .../reference/reachabilityChecks6.errors.txt | 5 +- .../baselines/reference/typeGuardEnums.types | 4 +- .../reference/typeGuardNesting.types | 10 +- .../typeGuardOfFormExpr1AndExpr2.types | 10 +- .../reference/typeGuardOfFormNotExpr.types | 14 +- .../reference/typeGuardRedundancy.types | 2 +- .../typeofOperatorWithAnyOtherType.errors.txt | 16 +- .../typeofOperatorWithStringType.errors.txt | 16 +- 32 files changed, 324 insertions(+), 834 deletions(-) create mode 100644 tests/baselines/reference/nestedBlockScopedBindings13.errors.txt delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings13.symbols delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings13.types create mode 100644 tests/baselines/reference/nestedBlockScopedBindings14.errors.txt delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings14.symbols delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings14.types create mode 100644 tests/baselines/reference/nestedBlockScopedBindings15.errors.txt delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings15.symbols delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings15.types create mode 100644 tests/baselines/reference/nestedBlockScopedBindings16.errors.txt delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings16.symbols delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings16.types create mode 100644 tests/baselines/reference/nestedBlockScopedBindings5.errors.txt delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings5.symbols delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings5.types create mode 100644 tests/baselines/reference/nestedBlockScopedBindings7.errors.txt delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings7.symbols delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings7.types create mode 100644 tests/baselines/reference/nestedBlockScopedBindings8.errors.txt delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings8.symbols delete mode 100644 tests/baselines/reference/nestedBlockScopedBindings8.types diff --git a/tests/baselines/reference/nestedBlockScopedBindings13.errors.txt b/tests/baselines/reference/nestedBlockScopedBindings13.errors.txt new file mode 100644 index 00000000000..0421583cff9 --- /dev/null +++ b/tests/baselines/reference/nestedBlockScopedBindings13.errors.txt @@ -0,0 +1,18 @@ +tests/cases/compiler/nestedBlockScopedBindings13.ts(2,5): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings13.ts(7,5): error TS7027: Unreachable code detected. + + +==== tests/cases/compiler/nestedBlockScopedBindings13.ts (2 errors) ==== + for (; false;) { + let x; + ~~~ +!!! error TS7027: Unreachable code detected. + () => x; + } + + for (; false;) { + let y; + ~~~ +!!! error TS7027: Unreachable code detected. + y = 1; + } \ No newline at end of file diff --git a/tests/baselines/reference/nestedBlockScopedBindings13.symbols b/tests/baselines/reference/nestedBlockScopedBindings13.symbols deleted file mode 100644 index a5bc7ed7866..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings13.symbols +++ /dev/null @@ -1,16 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings13.ts === -for (; false;) { - let x; ->x : Symbol(x, Decl(nestedBlockScopedBindings13.ts, 1, 7)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings13.ts, 1, 7)) -} - -for (; false;) { - let y; ->y : Symbol(y, Decl(nestedBlockScopedBindings13.ts, 6, 7)) - - y = 1; ->y : Symbol(y, Decl(nestedBlockScopedBindings13.ts, 6, 7)) -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings13.types b/tests/baselines/reference/nestedBlockScopedBindings13.types deleted file mode 100644 index 2e7bc7de77e..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings13.types +++ /dev/null @@ -1,23 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings13.ts === -for (; false;) { ->false : boolean - - let x; ->x : any - - () => x; ->() => x : () => any ->x : any -} - -for (; false;) { ->false : boolean - - let y; ->y : any - - y = 1; ->y = 1 : number ->y : any ->1 : number -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings14.errors.txt b/tests/baselines/reference/nestedBlockScopedBindings14.errors.txt new file mode 100644 index 00000000000..1b5babb4c25 --- /dev/null +++ b/tests/baselines/reference/nestedBlockScopedBindings14.errors.txt @@ -0,0 +1,20 @@ +tests/cases/compiler/nestedBlockScopedBindings14.ts(3,5): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings14.ts(9,5): error TS7027: Unreachable code detected. + + +==== tests/cases/compiler/nestedBlockScopedBindings14.ts (2 errors) ==== + var x; + for (; false;) { + let x; + ~~~ +!!! error TS7027: Unreachable code detected. + () => x; + } + + var y; + for (; false;) { + let y; + ~~~ +!!! error TS7027: Unreachable code detected. + y = 1; + } \ No newline at end of file diff --git a/tests/baselines/reference/nestedBlockScopedBindings14.symbols b/tests/baselines/reference/nestedBlockScopedBindings14.symbols deleted file mode 100644 index 4a13b296e88..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings14.symbols +++ /dev/null @@ -1,22 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings14.ts === -var x; ->x : Symbol(x, Decl(nestedBlockScopedBindings14.ts, 0, 3)) - -for (; false;) { - let x; ->x : Symbol(x, Decl(nestedBlockScopedBindings14.ts, 2, 7)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings14.ts, 2, 7)) -} - -var y; ->y : Symbol(y, Decl(nestedBlockScopedBindings14.ts, 6, 3)) - -for (; false;) { - let y; ->y : Symbol(y, Decl(nestedBlockScopedBindings14.ts, 8, 7)) - - y = 1; ->y : Symbol(y, Decl(nestedBlockScopedBindings14.ts, 8, 7)) -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings14.types b/tests/baselines/reference/nestedBlockScopedBindings14.types deleted file mode 100644 index 966eaaaac7a..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings14.types +++ /dev/null @@ -1,29 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings14.ts === -var x; ->x : any - -for (; false;) { ->false : boolean - - let x; ->x : any - - () => x; ->() => x : () => any ->x : any -} - -var y; ->y : any - -for (; false;) { ->false : boolean - - let y; ->y : any - - y = 1; ->y = 1 : number ->y : any ->1 : number -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings15.errors.txt b/tests/baselines/reference/nestedBlockScopedBindings15.errors.txt new file mode 100644 index 00000000000..b60a502b528 --- /dev/null +++ b/tests/baselines/reference/nestedBlockScopedBindings15.errors.txt @@ -0,0 +1,46 @@ +tests/cases/compiler/nestedBlockScopedBindings15.ts(3,9): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings15.ts(10,9): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings15.ts(16,5): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings15.ts(25,5): error TS7027: Unreachable code detected. + + +==== tests/cases/compiler/nestedBlockScopedBindings15.ts (4 errors) ==== + for (; false;) { + { + let x; + ~~~ +!!! error TS7027: Unreachable code detected. + () => x; + } + } + + for (; false;) { + { + let y; + ~~~ +!!! error TS7027: Unreachable code detected. + y = 1; + } + } + + for (; false;) { + switch (1){ + ~~~~~~ +!!! error TS7027: Unreachable code detected. + case 1: + let z0; + () => z0; + break; + } + } + + for (; false;) { + switch (1){ + ~~~~~~ +!!! error TS7027: Unreachable code detected. + case 1: + let z; + z = 1; + break; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/nestedBlockScopedBindings15.symbols b/tests/baselines/reference/nestedBlockScopedBindings15.symbols deleted file mode 100644 index 26ef28f6050..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings15.symbols +++ /dev/null @@ -1,46 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings15.ts === -for (; false;) { - { - let x; ->x : Symbol(x, Decl(nestedBlockScopedBindings15.ts, 2, 11)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings15.ts, 2, 11)) - } -} - -for (; false;) { - { - let y; ->y : Symbol(y, Decl(nestedBlockScopedBindings15.ts, 9, 11)) - - y = 1; ->y : Symbol(y, Decl(nestedBlockScopedBindings15.ts, 9, 11)) - } -} - -for (; false;) { - switch (1){ - case 1: - let z0; ->z0 : Symbol(z0, Decl(nestedBlockScopedBindings15.ts, 17, 15)) - - () => z0; ->z0 : Symbol(z0, Decl(nestedBlockScopedBindings15.ts, 17, 15)) - - break; - } -} - -for (; false;) { - switch (1){ - case 1: - let z; ->z : Symbol(z, Decl(nestedBlockScopedBindings15.ts, 26, 15)) - - z = 1; ->z : Symbol(z, Decl(nestedBlockScopedBindings15.ts, 26, 15)) - - break; - } -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings15.types b/tests/baselines/reference/nestedBlockScopedBindings15.types deleted file mode 100644 index 5173c0c5600..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings15.types +++ /dev/null @@ -1,66 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings15.ts === -for (; false;) { ->false : boolean - { - let x; ->x : any - - () => x; ->() => x : () => any ->x : any - } -} - -for (; false;) { ->false : boolean - { - let y; ->y : any - - y = 1; ->y = 1 : number ->y : any ->1 : number - } -} - -for (; false;) { ->false : boolean - - switch (1){ ->1 : number - - case 1: ->1 : number - - let z0; ->z0 : any - - () => z0; ->() => z0 : () => any ->z0 : any - - break; - } -} - -for (; false;) { ->false : boolean - - switch (1){ ->1 : number - - case 1: ->1 : number - - let z; ->z : any - - z = 1; ->z = 1 : number ->z : any ->1 : number - - break; - } -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings16.errors.txt b/tests/baselines/reference/nestedBlockScopedBindings16.errors.txt new file mode 100644 index 00000000000..806f58231a0 --- /dev/null +++ b/tests/baselines/reference/nestedBlockScopedBindings16.errors.txt @@ -0,0 +1,50 @@ +tests/cases/compiler/nestedBlockScopedBindings16.ts(4,9): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings16.ts(12,9): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings16.ts(19,5): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings16.ts(29,5): error TS7027: Unreachable code detected. + + +==== tests/cases/compiler/nestedBlockScopedBindings16.ts (4 errors) ==== + var x; + for (; false;) { + { + let x; + ~~~ +!!! error TS7027: Unreachable code detected. + () => x; + } + } + + var y; + for (; false;) { + { + let y; + ~~~ +!!! error TS7027: Unreachable code detected. + y = 1; + } + } + + var z0; + for (; false;) { + switch (1){ + ~~~~~~ +!!! error TS7027: Unreachable code detected. + case 1: + let z0; + () => z0; + break; + } + } + + var z; + for (; false;) { + switch (1){ + ~~~~~~ +!!! error TS7027: Unreachable code detected. + case 1: + let z; + z = 1; + break; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/nestedBlockScopedBindings16.symbols b/tests/baselines/reference/nestedBlockScopedBindings16.symbols deleted file mode 100644 index cbe8114cf14..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings16.symbols +++ /dev/null @@ -1,58 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings16.ts === -var x; ->x : Symbol(x, Decl(nestedBlockScopedBindings16.ts, 0, 3)) - -for (; false;) { - { - let x; ->x : Symbol(x, Decl(nestedBlockScopedBindings16.ts, 3, 11)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings16.ts, 3, 11)) - } -} - -var y; ->y : Symbol(y, Decl(nestedBlockScopedBindings16.ts, 8, 3)) - -for (; false;) { - { - let y; ->y : Symbol(y, Decl(nestedBlockScopedBindings16.ts, 11, 11)) - - y = 1; ->y : Symbol(y, Decl(nestedBlockScopedBindings16.ts, 11, 11)) - } -} - -var z0; ->z0 : Symbol(z0, Decl(nestedBlockScopedBindings16.ts, 16, 3)) - -for (; false;) { - switch (1){ - case 1: - let z0; ->z0 : Symbol(z0, Decl(nestedBlockScopedBindings16.ts, 20, 15)) - - () => z0; ->z0 : Symbol(z0, Decl(nestedBlockScopedBindings16.ts, 20, 15)) - - break; - } -} - -var z; ->z : Symbol(z, Decl(nestedBlockScopedBindings16.ts, 26, 3)) - -for (; false;) { - switch (1){ - case 1: - let z; ->z : Symbol(z, Decl(nestedBlockScopedBindings16.ts, 30, 15)) - - z = 1; ->z : Symbol(z, Decl(nestedBlockScopedBindings16.ts, 30, 15)) - - break; - } -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings16.types b/tests/baselines/reference/nestedBlockScopedBindings16.types deleted file mode 100644 index 22698402a62..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings16.types +++ /dev/null @@ -1,78 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings16.ts === -var x; ->x : any - -for (; false;) { ->false : boolean - { - let x; ->x : any - - () => x; ->() => x : () => any ->x : any - } -} - -var y; ->y : any - -for (; false;) { ->false : boolean - { - let y; ->y : any - - y = 1; ->y = 1 : number ->y : any ->1 : number - } -} - -var z0; ->z0 : any - -for (; false;) { ->false : boolean - - switch (1){ ->1 : number - - case 1: ->1 : number - - let z0; ->z0 : any - - () => z0; ->() => z0 : () => any ->z0 : any - - break; - } -} - -var z; ->z : any - -for (; false;) { ->false : boolean - - switch (1){ ->1 : number - - case 1: ->1 : number - - let z; ->z : any - - z = 1; ->z = 1 : number ->z : any ->1 : number - - break; - } -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings5.errors.txt b/tests/baselines/reference/nestedBlockScopedBindings5.errors.txt new file mode 100644 index 00000000000..a40f6a29aea --- /dev/null +++ b/tests/baselines/reference/nestedBlockScopedBindings5.errors.txt @@ -0,0 +1,92 @@ +tests/cases/compiler/nestedBlockScopedBindings5.ts(37,9): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings5.ts(54,9): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings5.ts(71,9): error TS7027: Unreachable code detected. + + +==== tests/cases/compiler/nestedBlockScopedBindings5.ts (3 errors) ==== + function a0() { + for (let x in []) { + x = x + 1; + } + for (let x;;) { + x = x + 2; + } + } + + function a1() { + for (let x in []) { + x = x + 1; + () => x; + } + for (let x;;) { + x = x + 2; + } + } + + function a2() { + for (let x in []) { + x = x + 1; + } + for (let x;;) { + x = x + 2; + () => x; + } + } + + + function a3() { + for (let x in []) { + x = x + 1; + () => x; + } + for (let x;false;) { + x = x + 2; + ~ +!!! error TS7027: Unreachable code detected. + () => x; + } + switch (1) { + case 1: + let x; + () => x; + break; + } + + } + + function a4() { + for (let x in []) { + x = x + 1; + } + for (let x;false;) { + x = x + 2; + ~ +!!! error TS7027: Unreachable code detected. + } + switch (1) { + case 1: + let x; + () => x; + break; + } + + } + + function a5() { + let y; + for (let x in []) { + x = x + 1; + } + for (let x;false;) { + x = x + 2; + ~ +!!! error TS7027: Unreachable code detected. + () => x; + } + switch (1) { + case 1: + let x; + break; + } + + } \ No newline at end of file diff --git a/tests/baselines/reference/nestedBlockScopedBindings5.symbols b/tests/baselines/reference/nestedBlockScopedBindings5.symbols deleted file mode 100644 index 202a1d2e83f..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings5.symbols +++ /dev/null @@ -1,163 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings5.ts === -function a0() { ->a0 : Symbol(a0, Decl(nestedBlockScopedBindings5.ts, 0, 0)) - - for (let x in []) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 1, 12)) - - x = x + 1; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 1, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 1, 12)) - } - for (let x;;) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 4, 12)) - - x = x + 2; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 4, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 4, 12)) - } -} - -function a1() { ->a1 : Symbol(a1, Decl(nestedBlockScopedBindings5.ts, 7, 1)) - - for (let x in []) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 10, 12)) - - x = x + 1; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 10, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 10, 12)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 10, 12)) - } - for (let x;;) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 14, 12)) - - x = x + 2; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 14, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 14, 12)) - } -} - -function a2() { ->a2 : Symbol(a2, Decl(nestedBlockScopedBindings5.ts, 17, 1)) - - for (let x in []) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 20, 12)) - - x = x + 1; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 20, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 20, 12)) - } - for (let x;;) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 23, 12)) - - x = x + 2; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 23, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 23, 12)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 23, 12)) - } -} - - -function a3() { ->a3 : Symbol(a3, Decl(nestedBlockScopedBindings5.ts, 27, 1)) - - for (let x in []) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 31, 12)) - - x = x + 1; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 31, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 31, 12)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 31, 12)) - } - for (let x;false;) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 35, 12)) - - x = x + 2; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 35, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 35, 12)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 35, 12)) - } - switch (1) { - case 1: - let x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 41, 15)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 41, 15)) - - break; - } - -} - -function a4() { ->a4 : Symbol(a4, Decl(nestedBlockScopedBindings5.ts, 46, 1)) - - for (let x in []) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 49, 12)) - - x = x + 1; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 49, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 49, 12)) - } - for (let x;false;) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 52, 12)) - - x = x + 2; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 52, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 52, 12)) - } - switch (1) { - case 1: - let x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 57, 15)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 57, 15)) - - break; - } - -} - -function a5() { ->a5 : Symbol(a5, Decl(nestedBlockScopedBindings5.ts, 62, 1)) - - let y; ->y : Symbol(y, Decl(nestedBlockScopedBindings5.ts, 65, 7)) - - for (let x in []) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 66, 12)) - - x = x + 1; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 66, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 66, 12)) - } - for (let x;false;) { ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 69, 12)) - - x = x + 2; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 69, 12)) ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 69, 12)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 69, 12)) - } - switch (1) { - case 1: - let x; ->x : Symbol(x, Decl(nestedBlockScopedBindings5.ts, 75, 15)) - - break; - } - -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings5.types b/tests/baselines/reference/nestedBlockScopedBindings5.types deleted file mode 100644 index 10ea0e5f902..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings5.types +++ /dev/null @@ -1,227 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings5.ts === -function a0() { ->a0 : () => void - - for (let x in []) { ->x : string ->[] : undefined[] - - x = x + 1; ->x = x + 1 : string ->x : string ->x + 1 : string ->x : string ->1 : number - } - for (let x;;) { ->x : any - - x = x + 2; ->x = x + 2 : any ->x : any ->x + 2 : any ->x : any ->2 : number - } -} - -function a1() { ->a1 : () => void - - for (let x in []) { ->x : string ->[] : undefined[] - - x = x + 1; ->x = x + 1 : string ->x : string ->x + 1 : string ->x : string ->1 : number - - () => x; ->() => x : () => string ->x : string - } - for (let x;;) { ->x : any - - x = x + 2; ->x = x + 2 : any ->x : any ->x + 2 : any ->x : any ->2 : number - } -} - -function a2() { ->a2 : () => void - - for (let x in []) { ->x : string ->[] : undefined[] - - x = x + 1; ->x = x + 1 : string ->x : string ->x + 1 : string ->x : string ->1 : number - } - for (let x;;) { ->x : any - - x = x + 2; ->x = x + 2 : any ->x : any ->x + 2 : any ->x : any ->2 : number - - () => x; ->() => x : () => any ->x : any - } -} - - -function a3() { ->a3 : () => void - - for (let x in []) { ->x : string ->[] : undefined[] - - x = x + 1; ->x = x + 1 : string ->x : string ->x + 1 : string ->x : string ->1 : number - - () => x; ->() => x : () => string ->x : string - } - for (let x;false;) { ->x : any ->false : boolean - - x = x + 2; ->x = x + 2 : any ->x : any ->x + 2 : any ->x : any ->2 : number - - () => x; ->() => x : () => any ->x : any - } - switch (1) { ->1 : number - - case 1: ->1 : number - - let x; ->x : any - - () => x; ->() => x : () => any ->x : any - - break; - } - -} - -function a4() { ->a4 : () => void - - for (let x in []) { ->x : string ->[] : undefined[] - - x = x + 1; ->x = x + 1 : string ->x : string ->x + 1 : string ->x : string ->1 : number - } - for (let x;false;) { ->x : any ->false : boolean - - x = x + 2; ->x = x + 2 : any ->x : any ->x + 2 : any ->x : any ->2 : number - } - switch (1) { ->1 : number - - case 1: ->1 : number - - let x; ->x : any - - () => x; ->() => x : () => any ->x : any - - break; - } - -} - -function a5() { ->a5 : () => void - - let y; ->y : any - - for (let x in []) { ->x : string ->[] : undefined[] - - x = x + 1; ->x = x + 1 : string ->x : string ->x + 1 : string ->x : string ->1 : number - } - for (let x;false;) { ->x : any ->false : boolean - - x = x + 2; ->x = x + 2 : any ->x : any ->x + 2 : any ->x : any ->2 : number - - () => x; ->() => x : () => any ->x : any - } - switch (1) { ->1 : number - - case 1: ->1 : number - - let x; ->x : any - - break; - } - -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings7.errors.txt b/tests/baselines/reference/nestedBlockScopedBindings7.errors.txt new file mode 100644 index 00000000000..274ef8bf6c3 --- /dev/null +++ b/tests/baselines/reference/nestedBlockScopedBindings7.errors.txt @@ -0,0 +1,16 @@ +tests/cases/compiler/nestedBlockScopedBindings7.ts(2,5): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings7.ts(6,5): error TS7027: Unreachable code detected. + + +==== tests/cases/compiler/nestedBlockScopedBindings7.ts (2 errors) ==== + for (let x; false;) { + () => x; + ~ +!!! error TS7027: Unreachable code detected. + } + + for (let y; false;) { + y = 1; + ~ +!!! error TS7027: Unreachable code detected. + } \ No newline at end of file diff --git a/tests/baselines/reference/nestedBlockScopedBindings7.symbols b/tests/baselines/reference/nestedBlockScopedBindings7.symbols deleted file mode 100644 index 2d65af06a96..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings7.symbols +++ /dev/null @@ -1,14 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings7.ts === -for (let x; false;) { ->x : Symbol(x, Decl(nestedBlockScopedBindings7.ts, 0, 8)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings7.ts, 0, 8)) -} - -for (let y; false;) { ->y : Symbol(y, Decl(nestedBlockScopedBindings7.ts, 4, 8)) - - y = 1; ->y : Symbol(y, Decl(nestedBlockScopedBindings7.ts, 4, 8)) -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings7.types b/tests/baselines/reference/nestedBlockScopedBindings7.types deleted file mode 100644 index 2fdb2d90e76..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings7.types +++ /dev/null @@ -1,19 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings7.ts === -for (let x; false;) { ->x : any ->false : boolean - - () => x; ->() => x : () => any ->x : any -} - -for (let y; false;) { ->y : any ->false : boolean - - y = 1; ->y = 1 : number ->y : any ->1 : number -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings8.errors.txt b/tests/baselines/reference/nestedBlockScopedBindings8.errors.txt new file mode 100644 index 00000000000..73f580ae3cb --- /dev/null +++ b/tests/baselines/reference/nestedBlockScopedBindings8.errors.txt @@ -0,0 +1,18 @@ +tests/cases/compiler/nestedBlockScopedBindings8.ts(3,5): error TS7027: Unreachable code detected. +tests/cases/compiler/nestedBlockScopedBindings8.ts(8,5): error TS7027: Unreachable code detected. + + +==== tests/cases/compiler/nestedBlockScopedBindings8.ts (2 errors) ==== + var x; + for (let x; false; ) { + () => x; + ~ +!!! error TS7027: Unreachable code detected. + } + + var y; + for (let y; false; ) { + y = 1; + ~ +!!! error TS7027: Unreachable code detected. + } \ No newline at end of file diff --git a/tests/baselines/reference/nestedBlockScopedBindings8.symbols b/tests/baselines/reference/nestedBlockScopedBindings8.symbols deleted file mode 100644 index a61df0502ec..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings8.symbols +++ /dev/null @@ -1,20 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings8.ts === -var x; ->x : Symbol(x, Decl(nestedBlockScopedBindings8.ts, 0, 3)) - -for (let x; false; ) { ->x : Symbol(x, Decl(nestedBlockScopedBindings8.ts, 1, 8)) - - () => x; ->x : Symbol(x, Decl(nestedBlockScopedBindings8.ts, 1, 8)) -} - -var y; ->y : Symbol(y, Decl(nestedBlockScopedBindings8.ts, 5, 3)) - -for (let y; false; ) { ->y : Symbol(y, Decl(nestedBlockScopedBindings8.ts, 6, 8)) - - y = 1; ->y : Symbol(y, Decl(nestedBlockScopedBindings8.ts, 6, 8)) -} diff --git a/tests/baselines/reference/nestedBlockScopedBindings8.types b/tests/baselines/reference/nestedBlockScopedBindings8.types deleted file mode 100644 index 9e4b98ffbf2..00000000000 --- a/tests/baselines/reference/nestedBlockScopedBindings8.types +++ /dev/null @@ -1,25 +0,0 @@ -=== tests/cases/compiler/nestedBlockScopedBindings8.ts === -var x; ->x : any - -for (let x; false; ) { ->x : any ->false : boolean - - () => x; ->() => x : () => any ->x : any -} - -var y; ->y : any - -for (let y; false; ) { ->y : any ->false : boolean - - y = 1; ->y = 1 : number ->y : any ->1 : number -} diff --git a/tests/baselines/reference/parser_duplicateLabel1.errors.txt b/tests/baselines/reference/parser_duplicateLabel1.errors.txt index a4319aaa7b9..c98ede21ecf 100644 --- a/tests/baselines/reference/parser_duplicateLabel1.errors.txt +++ b/tests/baselines/reference/parser_duplicateLabel1.errors.txt @@ -1,13 +1,16 @@ tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel1.ts(1,1): error TS7028: Unused label. tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel1.ts(2,1): error TS1114: Duplicate label 'target' +tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel1.ts(2,1): error TS7028: Unused label. -==== tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel1.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel1.ts (3 errors) ==== target: ~~~~~~ !!! error TS7028: Unused label. target: ~~~~~~ !!! error TS1114: Duplicate label 'target' + ~~~~~~ +!!! error TS7028: Unused label. while (true) { } \ No newline at end of file diff --git a/tests/baselines/reference/parser_duplicateLabel2.errors.txt b/tests/baselines/reference/parser_duplicateLabel2.errors.txt index 123949fa5aa..cbad8b73a21 100644 --- a/tests/baselines/reference/parser_duplicateLabel2.errors.txt +++ b/tests/baselines/reference/parser_duplicateLabel2.errors.txt @@ -1,8 +1,9 @@ tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel2.ts(1,1): error TS7028: Unused label. tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel2.ts(3,3): error TS1114: Duplicate label 'target' +tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel2.ts(3,3): error TS7028: Unused label. -==== tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel2.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel2.ts (3 errors) ==== target: ~~~~~~ !!! error TS7028: Unused label. @@ -10,6 +11,8 @@ tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_d target: ~~~~~~ !!! error TS1114: Duplicate label 'target' + ~~~~~~ +!!! error TS7028: Unused label. while (true) { } } \ No newline at end of file diff --git a/tests/baselines/reference/reachabilityChecks5.errors.txt b/tests/baselines/reference/reachabilityChecks5.errors.txt index 147dbe264a3..4a894261a3d 100644 --- a/tests/baselines/reference/reachabilityChecks5.errors.txt +++ b/tests/baselines/reference/reachabilityChecks5.errors.txt @@ -6,11 +6,12 @@ tests/cases/compiler/reachabilityChecks5.ts(52,17): error TS7030: Not all code p tests/cases/compiler/reachabilityChecks5.ts(80,17): error TS7030: Not all code paths return a value. tests/cases/compiler/reachabilityChecks5.ts(86,13): error TS7027: Unreachable code detected. tests/cases/compiler/reachabilityChecks5.ts(94,17): error TS7030: Not all code paths return a value. +tests/cases/compiler/reachabilityChecks5.ts(97,13): error TS7027: Unreachable code detected. tests/cases/compiler/reachabilityChecks5.ts(116,18): error TS7030: Not all code paths return a value. tests/cases/compiler/reachabilityChecks5.ts(123,13): error TS7027: Unreachable code detected. -==== tests/cases/compiler/reachabilityChecks5.ts (10 errors) ==== +==== tests/cases/compiler/reachabilityChecks5.ts (11 errors) ==== function f0(x): number { while (true); @@ -124,6 +125,8 @@ tests/cases/compiler/reachabilityChecks5.ts(123,13): error TS7027: Unreachable c try { while (false) { return 1; + ~~~~~~ +!!! error TS7027: Unreachable code detected. } } catch (e) { diff --git a/tests/baselines/reference/reachabilityChecks6.errors.txt b/tests/baselines/reference/reachabilityChecks6.errors.txt index 38e72def8c6..24832d9ab38 100644 --- a/tests/baselines/reference/reachabilityChecks6.errors.txt +++ b/tests/baselines/reference/reachabilityChecks6.errors.txt @@ -5,11 +5,12 @@ tests/cases/compiler/reachabilityChecks6.ts(52,10): error TS7030: Not all code p tests/cases/compiler/reachabilityChecks6.ts(80,10): error TS7030: Not all code paths return a value. tests/cases/compiler/reachabilityChecks6.ts(86,13): error TS7027: Unreachable code detected. tests/cases/compiler/reachabilityChecks6.ts(94,10): error TS7030: Not all code paths return a value. +tests/cases/compiler/reachabilityChecks6.ts(97,13): error TS7027: Unreachable code detected. tests/cases/compiler/reachabilityChecks6.ts(116,10): error TS7030: Not all code paths return a value. tests/cases/compiler/reachabilityChecks6.ts(123,13): error TS7027: Unreachable code detected. -==== tests/cases/compiler/reachabilityChecks6.ts (9 errors) ==== +==== tests/cases/compiler/reachabilityChecks6.ts (10 errors) ==== function f0(x) { while (true); @@ -121,6 +122,8 @@ tests/cases/compiler/reachabilityChecks6.ts(123,13): error TS7027: Unreachable c try { while (false) { return 1; + ~~~~~~ +!!! error TS7027: Unreachable code detected. } } catch (e) { diff --git a/tests/baselines/reference/typeGuardEnums.types b/tests/baselines/reference/typeGuardEnums.types index 1d39a81d78a..2bef6915046 100644 --- a/tests/baselines/reference/typeGuardEnums.types +++ b/tests/baselines/reference/typeGuardEnums.types @@ -27,7 +27,7 @@ else { if (typeof x !== "number") { >typeof x !== "number" : boolean >typeof x : string ->x : number | string | E | V +>x : number | string >"number" : string x; // string @@ -35,6 +35,6 @@ if (typeof x !== "number") { } else { x; // number|E|V ->x : number | E | V +>x : number } diff --git a/tests/baselines/reference/typeGuardNesting.types b/tests/baselines/reference/typeGuardNesting.types index 255e96da89e..2b18e232412 100644 --- a/tests/baselines/reference/typeGuardNesting.types +++ b/tests/baselines/reference/typeGuardNesting.types @@ -34,7 +34,7 @@ if ((typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'stri >(typeof strOrBool === 'boolean') : boolean >typeof strOrBool === 'boolean' : boolean >typeof strOrBool : string ->strOrBool : boolean | string +>strOrBool : string | boolean >'boolean' : string >strOrBool : boolean >false : boolean @@ -56,7 +56,7 @@ if ((typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'stri >(typeof strOrBool !== 'string') : boolean >typeof strOrBool !== 'string' : boolean >typeof strOrBool : string ->strOrBool : boolean | string +>strOrBool : string | boolean >'string' : string >strOrBool : boolean >false : boolean @@ -68,7 +68,7 @@ if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boole >typeof strOrBool !== 'string' && !strOrBool : boolean >typeof strOrBool !== 'string' : boolean >typeof strOrBool : string ->strOrBool : string | boolean +>strOrBool : boolean | string >'string' : string >!strOrBool : boolean >strOrBool : boolean @@ -94,7 +94,7 @@ if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boole >(typeof strOrBool === 'boolean') : boolean >typeof strOrBool === 'boolean' : boolean >typeof strOrBool : string ->strOrBool : boolean | string +>strOrBool : string | boolean >'boolean' : string >strOrBool : boolean >false : boolean @@ -116,7 +116,7 @@ if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boole >(typeof strOrBool !== 'string') : boolean >typeof strOrBool !== 'string' : boolean >typeof strOrBool : string ->strOrBool : boolean | string +>strOrBool : string | boolean >'string' : string >strOrBool : boolean >false : boolean diff --git a/tests/baselines/reference/typeGuardOfFormExpr1AndExpr2.types b/tests/baselines/reference/typeGuardOfFormExpr1AndExpr2.types index 10f50bed52e..a10d398988f 100644 --- a/tests/baselines/reference/typeGuardOfFormExpr1AndExpr2.types +++ b/tests/baselines/reference/typeGuardOfFormExpr1AndExpr2.types @@ -95,11 +95,11 @@ if (typeof strOrNumOrBoolOrC !== "string" && typeof strOrNumOrBoolOrC !== "numbe >typeof strOrNumOrBoolOrC !== "string" && typeof strOrNumOrBoolOrC !== "number" : boolean >typeof strOrNumOrBoolOrC !== "string" : boolean >typeof strOrNumOrBoolOrC : string ->strOrNumOrBoolOrC : string | number | boolean | C +>strOrNumOrBoolOrC : C | string | number | boolean >"string" : string >typeof strOrNumOrBoolOrC !== "number" : boolean >typeof strOrNumOrBoolOrC : string ->strOrNumOrBoolOrC : number | boolean | C +>strOrNumOrBoolOrC : C | number | boolean >"number" : string >typeof strOrNumOrBool === "boolean" : boolean >typeof strOrNumOrBool : string @@ -107,9 +107,9 @@ if (typeof strOrNumOrBoolOrC !== "string" && typeof strOrNumOrBoolOrC !== "numbe >"boolean" : string cOrBool = strOrNumOrBoolOrC; // C | boolean ->cOrBool = strOrNumOrBoolOrC : boolean | C +>cOrBool = strOrNumOrBoolOrC : C | boolean >cOrBool : C | boolean ->strOrNumOrBoolOrC : boolean | C +>strOrNumOrBoolOrC : C | boolean bool = strOrNumOrBool; // boolean >bool = strOrNumOrBool : boolean @@ -120,7 +120,7 @@ else { var r1: string | number | boolean | C = strOrNumOrBoolOrC; // string | number | boolean | C >r1 : string | number | boolean | C >C : C ->strOrNumOrBoolOrC : string | number | boolean | C +>strOrNumOrBoolOrC : string | number | C | boolean var r2: string | number | boolean = strOrNumOrBool; >r2 : string | number | boolean diff --git a/tests/baselines/reference/typeGuardOfFormNotExpr.types b/tests/baselines/reference/typeGuardOfFormNotExpr.types index a99db08efab..e7cfd6a0dce 100644 --- a/tests/baselines/reference/typeGuardOfFormNotExpr.types +++ b/tests/baselines/reference/typeGuardOfFormNotExpr.types @@ -73,13 +73,13 @@ if (!(typeof strOrNumOrBool !== "string") || !(typeof strOrNumOrBool !== "number >(typeof strOrNumOrBool !== "string") : boolean >typeof strOrNumOrBool !== "string" : boolean >typeof strOrNumOrBool : string ->strOrNumOrBool : string | number | boolean +>strOrNumOrBool : boolean | string | number >"string" : string >!(typeof strOrNumOrBool !== "number") : boolean >(typeof strOrNumOrBool !== "number") : boolean >typeof strOrNumOrBool !== "number" : boolean >typeof strOrNumOrBool : string ->strOrNumOrBool : number | boolean +>strOrNumOrBool : boolean | number >"number" : string strOrNum = strOrNumOrBool; // string | number @@ -152,19 +152,19 @@ if (!(typeof strOrNumOrBool === "string") && numOrBool !== strOrNumOrBool) { >(typeof strOrNumOrBool === "string") : boolean >typeof strOrNumOrBool === "string" : boolean >typeof strOrNumOrBool : string ->strOrNumOrBool : string | number | boolean +>strOrNumOrBool : boolean | string | number >"string" : string >numOrBool !== strOrNumOrBool : boolean >numOrBool : number | boolean ->strOrNumOrBool : number | boolean +>strOrNumOrBool : boolean | number numOrBool = strOrNumOrBool; // number | boolean ->numOrBool = strOrNumOrBool : number | boolean +>numOrBool = strOrNumOrBool : boolean | number >numOrBool : number | boolean ->strOrNumOrBool : number | boolean +>strOrNumOrBool : boolean | number } else { var r1: string | number | boolean = strOrNumOrBool; // string | number | boolean >r1 : string | number | boolean ->strOrNumOrBool : string | number | boolean +>strOrNumOrBool : string | boolean | number } diff --git a/tests/baselines/reference/typeGuardRedundancy.types b/tests/baselines/reference/typeGuardRedundancy.types index 1507ceb850e..754019de7ed 100644 --- a/tests/baselines/reference/typeGuardRedundancy.types +++ b/tests/baselines/reference/typeGuardRedundancy.types @@ -48,7 +48,7 @@ var r3 = typeof x === "string" || typeof x === "string" ? x.substr : x.toFixed; >typeof x === "string" || typeof x === "string" : boolean >typeof x === "string" : boolean >typeof x : string ->x : string | number +>x : number | string >"string" : string >typeof x === "string" : boolean >typeof x : string diff --git a/tests/baselines/reference/typeofOperatorWithAnyOtherType.errors.txt b/tests/baselines/reference/typeofOperatorWithAnyOtherType.errors.txt index 0139c96b3f9..f9394c622c0 100644 --- a/tests/baselines/reference/typeofOperatorWithAnyOtherType.errors.txt +++ b/tests/baselines/reference/typeofOperatorWithAnyOtherType.errors.txt @@ -4,9 +4,13 @@ tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperator tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts(68,1): error TS7028: Unused label. tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts(69,1): error TS7028: Unused label. tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts(70,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts(71,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts(72,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts(73,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts(74,1): error TS7028: Unused label. -==== tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts (6 errors) ==== +==== tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithAnyOtherType.ts (10 errors) ==== // typeof operator on any type var ANY: any; @@ -90,6 +94,14 @@ tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperator ~ !!! error TS7028: Unused label. z: typeof objA.a; + ~ +!!! error TS7028: Unused label. z: typeof A.foo; + ~ +!!! error TS7028: Unused label. z: typeof M.n; - z: typeof obj1.x; \ No newline at end of file + ~ +!!! error TS7028: Unused label. + z: typeof obj1.x; + ~ +!!! error TS7028: Unused label. \ No newline at end of file diff --git a/tests/baselines/reference/typeofOperatorWithStringType.errors.txt b/tests/baselines/reference/typeofOperatorWithStringType.errors.txt index 37b2cafab37..bd891c949a3 100644 --- a/tests/baselines/reference/typeofOperatorWithStringType.errors.txt +++ b/tests/baselines/reference/typeofOperatorWithStringType.errors.txt @@ -1,9 +1,13 @@ tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts(50,1): error TS7028: Unused label. tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts(51,1): error TS7028: Unused label. tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts(52,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts(54,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts(55,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts(56,1): error TS7028: Unused label. +tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts(57,1): error TS7028: Unused label. -==== tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts (3 errors) ==== +==== tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperatorWithStringType.ts (7 errors) ==== // typeof operator on string type var STRING: string; var STRING1: string[] = ["", "abc"]; @@ -64,6 +68,14 @@ tests/cases/conformance/expressions/unaryOperators/typeofOperator/typeofOperator !!! error TS7028: Unused label. var y = { a: "", b: "" }; z: typeof y.a; + ~ +!!! error TS7028: Unused label. z: typeof objA.a; + ~ +!!! error TS7028: Unused label. z: typeof A.foo; - z: typeof M.n; \ No newline at end of file + ~ +!!! error TS7028: Unused label. + z: typeof M.n; + ~ +!!! error TS7028: Unused label. \ No newline at end of file From 33985b24b7eb6b00ca256025f445addb9db67066 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 24 Mar 2016 06:50:01 -0700 Subject: [PATCH 009/110] Adding a few optimizations --- src/compiler/checker.ts | 10 +++++----- src/compiler/types.ts | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index da5cc90caa4..7540482183d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7231,7 +7231,7 @@ namespace ts { } function getAssignmentReducedType(type: Type, assignedType: Type) { - if (type.flags & TypeFlags.Union) { + if (type !== assignedType && type.flags & TypeFlags.Union) { const reducedTypes = filter((type).types, t => isTypeAssignableTo(assignedType, t)); if (reducedTypes.length) { return reducedTypes.length === 1 ? reducedTypes[0] : getUnionType(reducedTypes); @@ -7241,10 +7241,7 @@ namespace ts { } function getNarrowedTypeOfReference(type: Type, reference: Node) { - if (!(type.flags & (TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter))) { - return type; - } - if (!isNarrowableReference(reference)) { + if (!(type.flags & TypeFlags.Narrowable) || !isNarrowableReference(reference)) { return type; } const leftmostNode = getLeftmostIdentifierOrThis(reference); @@ -7721,6 +7718,9 @@ namespace ts { const defaultsToDeclaredType = !strictNullChecks || !declaration || declaration.kind === SyntaxKind.Parameter || isInAmbientContext(declaration) || getContainingFunction(declaration) !== getContainingFunction(node); + if (defaultsToDeclaredType && !(type.flags & TypeFlags.Narrowable)) { + return type; + } const flowType = getFlowTypeOfReference(node, type, defaultsToDeclaredType ? type : undefinedType); if (strictNullChecks && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) { error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c850fe47012..ed82d65d5dd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2176,6 +2176,7 @@ namespace ts { ObjectType = Class | Interface | Reference | Tuple | Anonymous, UnionOrIntersection = Union | Intersection, StructuredType = ObjectType | Union | Intersection, + Narrowable = Any | ObjectType | Union | TypeParameter, /* @internal */ RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral, /* @internal */ From ed5002c81a1c231f0184e3b40ec00fb54c15750e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 24 Mar 2016 22:03:53 -0700 Subject: [PATCH 010/110] Handle assignment of union types in getAssignmentReducedType --- src/compiler/checker.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7540482183d..ff37cd9f2b7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7230,14 +7230,29 @@ namespace ts { expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((expr).expression); } - function getAssignmentReducedType(type: Type, assignedType: Type) { - if (type !== assignedType && type.flags & TypeFlags.Union) { - const reducedTypes = filter((type).types, t => isTypeAssignableTo(assignedType, t)); + function typeMaybeAssignableTo(source: Type, target: Type) { + if (!(source.flags & TypeFlags.Union)) { + return isTypeAssignableTo(source, target); + } + for (const t of (source).types) { + if (isTypeAssignableTo(t, target)) { + return true; + } + } + return false; + } + + // Remove those constituent types of currentType to which no constituent type of assignedType is assignable. + // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, + // we remove type string. + function getAssignmentReducedType(currentType: Type, assignedType: Type) { + if (currentType !== assignedType && currentType.flags & TypeFlags.Union) { + const reducedTypes = filter((currentType).types, t => typeMaybeAssignableTo(assignedType, t)); if (reducedTypes.length) { return reducedTypes.length === 1 ? reducedTypes[0] : getUnionType(reducedTypes); } } - return type; + return currentType; } function getNarrowedTypeOfReference(type: Type, reference: Node) { From 6d25a42fd99115ddf32c378a37a1d086174c470f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 24 Mar 2016 22:04:44 -0700 Subject: [PATCH 011/110] Remove incorrect type predicate (could be true even when result is false) --- src/compiler/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2966af3cb76..da33c18dfb8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1412,7 +1412,7 @@ namespace ts { } // True if the given identifier, string literal, or number literal is the name of a declaration node - export function isDeclarationName(name: Node): name is Identifier | StringLiteral | LiteralExpression { + export function isDeclarationName(name: Node): boolean { if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) { return false; } From bf78470ed36ff629ffad3142b7a6ffd5f875936d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 25 Mar 2016 10:47:04 -0700 Subject: [PATCH 012/110] Fix overly aggressive optimization --- src/compiler/checker.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ff37cd9f2b7..9ae6faeff74 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7242,17 +7242,17 @@ namespace ts { return false; } - // Remove those constituent types of currentType to which no constituent type of assignedType is assignable. + // Remove those constituent types of declaredType to which no constituent type of assignedType is assignable. // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, // we remove type string. - function getAssignmentReducedType(currentType: Type, assignedType: Type) { - if (currentType !== assignedType && currentType.flags & TypeFlags.Union) { - const reducedTypes = filter((currentType).types, t => typeMaybeAssignableTo(assignedType, t)); + function getAssignmentReducedType(declaredType: Type, assignedType: Type) { + if (declaredType !== assignedType && declaredType.flags & TypeFlags.Union) { + const reducedTypes = filter((declaredType).types, t => typeMaybeAssignableTo(assignedType, t)); if (reducedTypes.length) { return reducedTypes.length === 1 ? reducedTypes[0] : getUnionType(reducedTypes); } } - return currentType; + return declaredType; } function getNarrowedTypeOfReference(type: Type, reference: Node) { @@ -7389,10 +7389,11 @@ namespace ts { for (const antecedent of flow.antecedents) { const t = getTypeAtFlowNodeCached(antecedent); if (t !== resolvingFlowType) { - // If the type at a particular antecedent path is the declared type, there is no - // reason to process more antecedents since the only possible outcome is subtypes - // that are be removed in the final union type anyway. - if (t === declaredType) { + // If the type at a particular antecedent path is the declared type and the + // reference is known to always be assigned (i.e. when declared and initial types + // are the same), there is no reason to process more antecedents since the only + // possible outcome is subtypes that will be removed in the final union type anyway. + if (t === declaredType && declaredType === initialType) { return t; } if (!contains(antecedentTypes, t)) { From 4f936c468b89eeded5e87fc71232220946861021 Mon Sep 17 00:00:00 2001 From: Ivo Gabe de Wolff Date: Fri, 25 Mar 2016 21:29:58 +0100 Subject: [PATCH 013/110] Add control flow tests --- .../controlFlowAssignmentExpression.ts | 10 +++ .../controlFlowBinaryAndExpression.ts | 9 +++ .../controlFlowBinaryOrExpression.ts | 9 +++ .../controlFlowConditionalExpression.ts | 5 ++ .../controlFlowDoWhileStatement.ts | 76 +++++++++++++++++++ .../controlFlow/controlFlowForInStatement.ts | 17 +++++ .../controlFlow/controlFlowForOfStatement.ts | 10 +++ .../controlFlow/controlFlowForStatement.ts | 41 ++++++++++ .../controlFlow/controlFlowIfStatement.ts | 36 +++++++++ .../controlFlow/controlFlowWhileStatement.ts | 75 ++++++++++++++++++ .../assignmentTypeNarrowing.ts | 28 +++++++ .../typeGuards/typeGuardsInDoStatement.ts | 27 +++++++ .../typeGuards/typeGuardsInForStatement.ts | 21 +++++ .../typeGuards/typeGuardsInWhileStatement.ts | 24 ++++++ 14 files changed, 388 insertions(+) create mode 100644 tests/cases/conformance/controlFlow/controlFlowAssignmentExpression.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowBinaryAndExpression.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowConditionalExpression.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowDoWhileStatement.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowForInStatement.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowForStatement.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowIfStatement.ts create mode 100644 tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts create mode 100644 tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardsInDoStatement.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardsInForStatement.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardsInWhileStatement.ts diff --git a/tests/cases/conformance/controlFlow/controlFlowAssignmentExpression.ts b/tests/cases/conformance/controlFlow/controlFlowAssignmentExpression.ts new file mode 100644 index 00000000000..83bf75ab94d --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowAssignmentExpression.ts @@ -0,0 +1,10 @@ +let x: string | boolean | number; +let obj: any; + +x = ""; +x = x.length; +x; // number + +x = true; +(x = "", obj).foo = (x = x.length); +x; // number diff --git a/tests/cases/conformance/controlFlow/controlFlowBinaryAndExpression.ts b/tests/cases/conformance/controlFlow/controlFlowBinaryAndExpression.ts new file mode 100644 index 00000000000..caaef9b890f --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowBinaryAndExpression.ts @@ -0,0 +1,9 @@ +let x: string | number | boolean; +let cond: boolean; + +(x = "") && (x = 0); +x; // string | number + +x = ""; +cond && (x = 0); +x; // string | number diff --git a/tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts b/tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts new file mode 100644 index 00000000000..75b24622e00 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts @@ -0,0 +1,9 @@ +let x: string | number | boolean; +let cond: boolean; + +(x = "") || (x = 0); +x; // string | number + +x = ""; +cond || (x = 0); +x; // string | number diff --git a/tests/cases/conformance/controlFlow/controlFlowConditionalExpression.ts b/tests/cases/conformance/controlFlow/controlFlowConditionalExpression.ts new file mode 100644 index 00000000000..c1c1d9956ea --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowConditionalExpression.ts @@ -0,0 +1,5 @@ +let x: string | number | boolean; +let cond: boolean; + +cond ? x = "" : x = 3; +x; // string | number diff --git a/tests/cases/conformance/controlFlow/controlFlowDoWhileStatement.ts b/tests/cases/conformance/controlFlow/controlFlowDoWhileStatement.ts new file mode 100644 index 00000000000..bd253bc064d --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowDoWhileStatement.ts @@ -0,0 +1,76 @@ +let cond: boolean; +function a() { + let x: string | number; + x = ""; + do { + x; // string + } while (cond) +} +function b() { + let x: string | number; + x = ""; + do { + x; // string + x = 42; + break; + } while (cond) +} +function c() { + let x: string | number; + x = ""; + do { + x; // string + x = undefined; + if (typeof x === "string") continue; + break; + } while (cond) +} +function d() { + let x: string | number; + x = 1000; + do { + x; // number + x = ""; + } while (x = x.length) + x; // number +} +function e() { + let x: string | number; + x = ""; + do { + x = 42; + } while (cond) + x; // number +} +function f() { + let x: string | number | boolean | RegExp | Function; + x = ""; + do { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } while (cond) + x; // number | boolean | RegExp +} +function g() { + let x: string | number | boolean | RegExp | Function; + x = ""; + do { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } while (true) + x; // number +} diff --git a/tests/cases/conformance/controlFlow/controlFlowForInStatement.ts b/tests/cases/conformance/controlFlow/controlFlowForInStatement.ts new file mode 100644 index 00000000000..a22e79506c2 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowForInStatement.ts @@ -0,0 +1,17 @@ +let x: string | number | boolean | RegExp | Function; +let obj: any; +let cond: boolean; + +x = /a/; +for (let y in obj) { + x = y; + if (cond) { + x = 42; + continue; + } + if (cond) { + x = true; + break; + } +} +x; // RegExp | string | number | boolean diff --git a/tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts b/tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts new file mode 100644 index 00000000000..ac4c584e1dc --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts @@ -0,0 +1,10 @@ +let obj: number[]; +let x: string | number | boolean | RegExp; + +function a() { + x = true; + for (x of obj) { + x = x.toExponential(); + } + x; // number | boolean +} diff --git a/tests/cases/conformance/controlFlow/controlFlowForStatement.ts b/tests/cases/conformance/controlFlow/controlFlowForStatement.ts new file mode 100644 index 00000000000..d9e46781aa7 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowForStatement.ts @@ -0,0 +1,41 @@ +let cond: boolean; +function a() { + let x: string | number | boolean; + for (x = ""; cond; x = 5) { + x; // string | number + } +} +function b() { + let x: string | number | boolean; + for (x = 5; cond; x = x.length) { + x; // number + x = ""; + } +} +function c() { + let x: string | number | boolean; + for (x = 5; x = x.toExponential(); x = 5) { + x; // string + } +} +function d() { + let x: string | number | boolean; + for (x = ""; typeof x === "string"; x = 5) { + x; // string + } +} +function e() { + let x: string | number | boolean | RegExp; + for (x = "" || 0; typeof x !== "string"; x = "" || true) { + x; // number | boolean + } +} +function f() { + let x: string | number | boolean; + for (; typeof x !== "string";) { + x; // number | boolean + if (typeof x === "number") break; + x = undefined; + } + x; // string | number +} diff --git a/tests/cases/conformance/controlFlow/controlFlowIfStatement.ts b/tests/cases/conformance/controlFlow/controlFlowIfStatement.ts new file mode 100644 index 00000000000..c9e9be92f8e --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowIfStatement.ts @@ -0,0 +1,36 @@ +let x: string | number | boolean | RegExp; +let cond: boolean; + +x = /a/; +if (x /* RegExp */, (x = true)) { + x; // boolean + x = ""; +} +else { + x; // boolean + x = 42; +} +x; // string | number + +function a() { + let x: string | number; + if (cond) { + x = 42; + } + else { + x = ""; + return; + } + x; // number +} +function b() { + let x: string | number; + if (cond) { + x = 42; + throw ""; + } + else { + x = ""; + } + x; // string +} diff --git a/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts b/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts new file mode 100644 index 00000000000..697a867b886 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts @@ -0,0 +1,75 @@ +let cond: boolean; +function a() { + let x: string | number; + x = ""; + while (cond) { + x; // string + } +} +function b() { + let x: string | number; + x = ""; + while (cond) { + x; // string + x = 42; + break; + } +} +function c() { + let x: string | number; + x = ""; + while (cond) { + x; // string + x = undefined; + if (typeof x === "string") continue; + break; + } +} +function d() { + let x: string | number; + x = ""; + while (x = x.length) { + x; // number + x = ""; + } +} +function e() { + let x: string | number; + x = ""; + while (cond) { + x = 42; + } + x; // string | number +} +function f() { + let x: string | number | boolean | RegExp | Function; + x = ""; + while (cond) { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } + x; // string | number | boolean | RegExp +} +function g() { + let x: string | number | boolean | RegExp | Function; + x = ""; + while (true) { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } + x; // number +} diff --git a/tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts b/tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts new file mode 100644 index 00000000000..0e5e257635a --- /dev/null +++ b/tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts @@ -0,0 +1,28 @@ +let x: string | number | boolean | RegExp; + +x = ""; +x; // string + +[x] = [true]; +x; // boolean + +[x = ""] = [1]; +x; // string | number + +({x} = {x: true}); +x; // boolean + +({y: x} = {y: 1}); +x; // number + +({x = ""} = {x: true}); +x; // string | boolean + +({y: x = /a/} = {y: 1}); +x; // number | RegExp + +let a: string[]; + +for (x of a) { + x; // string +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsInDoStatement.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsInDoStatement.ts new file mode 100644 index 00000000000..1afbe515df8 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsInDoStatement.ts @@ -0,0 +1,27 @@ +let cond: boolean; +function a(x: string | number | boolean) { + x = true; + do { + x; // boolean | string + x = undefined; + } while (typeof x === "string") + x; // number | boolean +} +function b(x: string | number | boolean) { + x = true; + do { + x; // boolean | string + if (cond) continue; + x = undefined; + } while (typeof x === "string") + x; // number | boolean +} +function c(x: string | number) { + x = ""; + do { + x; // string + if (cond) break; + x = undefined; + } while (typeof x === "string") + x; // string | number +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsInForStatement.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsInForStatement.ts new file mode 100644 index 00000000000..cf5c008e800 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsInForStatement.ts @@ -0,0 +1,21 @@ +let cond: boolean; +function a(x: string | number) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + } + x; // number +} +function b(x: string | number) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + if (cond) continue; + } + x; // number +} +function c(x: string | number) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + if (cond) break; + } + x; // string | number +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsInWhileStatement.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsInWhileStatement.ts new file mode 100644 index 00000000000..642c8995795 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsInWhileStatement.ts @@ -0,0 +1,24 @@ +let cond: boolean; +function a(x: string | number) { + while (typeof x === "string") { + x; // string + x = undefined; + } + x; // number +} +function b(x: string | number) { + while (typeof x === "string") { + if (cond) continue; + x; // string + x = undefined; + } + x; // number +} +function c(x: string | number) { + while (typeof x === "string") { + if (cond) break; + x; // string + x = undefined; + } + x; // string | number +} From 9e965d408c840c87ab54511ebab6f22c57a75427 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 25 Mar 2016 17:03:00 -0700 Subject: [PATCH 014/110] Fix issues in analysis of do..while and for..in/for..of --- src/compiler/binder.ts | 13 +++++++++---- src/compiler/checker.ts | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b49e22e8192..cfeb76827bf 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -636,6 +636,9 @@ namespace ts { } function createFlowCondition(antecedent: FlowNode, expression: Expression, assumeTrue: boolean): FlowNode { + if (antecedent.kind === FlowKind.Unreachable) { + return antecedent; + } if (!expression) { return assumeTrue ? antecedent : unreachableFlow; } @@ -696,16 +699,19 @@ namespace ts { function bindDoStatement(node: DoStatement): void { const preDoLabel = createFlowLabel(); + const preConditionLabel = createFlowLabel(); const postDoLabel = createFlowLabel(); addAntecedent(preDoLabel, currentFlow); currentFlow = preDoLabel; const saveBreakTarget = breakTarget; const saveContinueTarget = continueTarget; breakTarget = postDoLabel; - continueTarget = preDoLabel; + continueTarget = preConditionLabel; bind(node.statement); breakTarget = saveBreakTarget; continueTarget = saveContinueTarget; + addAntecedent(preConditionLabel, currentFlow); + currentFlow = finishFlow(preConditionLabel); bind(node.expression); addAntecedent(preDoLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ true)); addAntecedent(postDoLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ false)); @@ -737,10 +743,10 @@ namespace ts { const preLoopLabel = createFlowLabel(); const postLoopLabel = createFlowLabel(); bind(node.initializer); - bind(node.expression); addAntecedent(preLoopLabel, currentFlow); - addAntecedent(postLoopLabel, currentFlow); currentFlow = preLoopLabel; + bind(node.expression); + addAntecedent(postLoopLabel, currentFlow); const saveBreakTarget = breakTarget; const saveContinueTarget = continueTarget; breakTarget = postLoopLabel; @@ -750,7 +756,6 @@ namespace ts { breakTarget = saveBreakTarget; continueTarget = saveContinueTarget; addAntecedent(preLoopLabel, currentFlow); - addAntecedent(postLoopLabel, currentFlow); currentFlow = finishFlow(postLoopLabel); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ae6faeff74..d8c62dd2da3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8674,7 +8674,9 @@ namespace ts { const parent = node.parent; return parent.kind === SyntaxKind.BinaryExpression && (parent).operatorToken.kind === SyntaxKind.EqualsToken && - (parent).left === node; + (parent).left === node || + (parent.kind === SyntaxKind.ForInStatement || parent.kind === SyntaxKind.ForOfStatement) && + (parent).initializer === node; } function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type { From 9de0a5d8331f3fd3266d85078ac72c2664efafcc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 25 Mar 2016 17:03:12 -0700 Subject: [PATCH 015/110] Fix comment in test --- .../cases/conformance/controlFlow/controlFlowForOfStatement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts b/tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts index ac4c584e1dc..3abcf814f2a 100644 --- a/tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts +++ b/tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts @@ -6,5 +6,5 @@ function a() { for (x of obj) { x = x.toExponential(); } - x; // number | boolean + x; // string | boolean } From 560bc3f38c845090b76eb08b8259551db8f36d95 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 25 Mar 2016 17:09:09 -0700 Subject: [PATCH 016/110] Accepting new baselines --- .../reference/TypeGuardWithEnumUnion.types | 10 +- .../controlFlowAssignmentExpression.js | 22 ++ .../controlFlowAssignmentExpression.symbols | 33 +++ .../controlFlowAssignmentExpression.types | 47 ++++ .../controlFlowBinaryAndExpression.js | 20 ++ .../controlFlowBinaryAndExpression.symbols | 24 ++ .../controlFlowBinaryAndExpression.types | 37 +++ .../controlFlowBinaryOrExpression.js | 20 ++ .../controlFlowBinaryOrExpression.symbols | 24 ++ .../controlFlowBinaryOrExpression.types | 37 +++ .../controlFlowConditionalExpression.js | 13 ++ .../controlFlowConditionalExpression.symbols | 15 ++ .../controlFlowConditionalExpression.types | 20 ++ .../reference/controlFlowDoWhileStatement.js | 157 +++++++++++++ .../controlFlowDoWhileStatement.symbols | 181 ++++++++++++++ .../controlFlowDoWhileStatement.types | 220 ++++++++++++++++++ .../reference/controlFlowForInStatement.js | 37 +++ .../controlFlowForInStatement.symbols | 43 ++++ .../reference/controlFlowForInStatement.types | 50 ++++ .../reference/controlFlowForOfStatement.js | 24 ++ .../controlFlowForOfStatement.symbols | 28 +++ .../reference/controlFlowForOfStatement.types | 32 +++ .../reference/controlFlowForStatement.js | 87 +++++++ .../reference/controlFlowForStatement.symbols | 112 +++++++++ .../reference/controlFlowForStatement.types | 152 ++++++++++++ .../reference/controlFlowIfStatement.js | 74 ++++++ .../reference/controlFlowIfStatement.symbols | 74 ++++++ .../reference/controlFlowIfStatement.types | 93 ++++++++ .../reference/controlFlowWhileStatement.js | 155 ++++++++++++ .../controlFlowWhileStatement.symbols | 177 ++++++++++++++ .../reference/controlFlowWhileStatement.types | 216 +++++++++++++++++ tests/baselines/reference/for-of45.types | 2 +- ...structuringForOfArrayBindingPattern2.types | 48 ++-- ...rOfArrayBindingPatternDefaultValues2.types | 36 +-- ...OfObjectBindingPatternDefaultValues2.types | 48 ++-- .../baselines/reference/systemModule13.types | 2 +- tests/baselines/reference/systemModule8.types | 2 +- 37 files changed, 2298 insertions(+), 74 deletions(-) create mode 100644 tests/baselines/reference/controlFlowAssignmentExpression.js create mode 100644 tests/baselines/reference/controlFlowAssignmentExpression.symbols create mode 100644 tests/baselines/reference/controlFlowAssignmentExpression.types create mode 100644 tests/baselines/reference/controlFlowBinaryAndExpression.js create mode 100644 tests/baselines/reference/controlFlowBinaryAndExpression.symbols create mode 100644 tests/baselines/reference/controlFlowBinaryAndExpression.types create mode 100644 tests/baselines/reference/controlFlowBinaryOrExpression.js create mode 100644 tests/baselines/reference/controlFlowBinaryOrExpression.symbols create mode 100644 tests/baselines/reference/controlFlowBinaryOrExpression.types create mode 100644 tests/baselines/reference/controlFlowConditionalExpression.js create mode 100644 tests/baselines/reference/controlFlowConditionalExpression.symbols create mode 100644 tests/baselines/reference/controlFlowConditionalExpression.types create mode 100644 tests/baselines/reference/controlFlowDoWhileStatement.js create mode 100644 tests/baselines/reference/controlFlowDoWhileStatement.symbols create mode 100644 tests/baselines/reference/controlFlowDoWhileStatement.types create mode 100644 tests/baselines/reference/controlFlowForInStatement.js create mode 100644 tests/baselines/reference/controlFlowForInStatement.symbols create mode 100644 tests/baselines/reference/controlFlowForInStatement.types create mode 100644 tests/baselines/reference/controlFlowForOfStatement.js create mode 100644 tests/baselines/reference/controlFlowForOfStatement.symbols create mode 100644 tests/baselines/reference/controlFlowForOfStatement.types create mode 100644 tests/baselines/reference/controlFlowForStatement.js create mode 100644 tests/baselines/reference/controlFlowForStatement.symbols create mode 100644 tests/baselines/reference/controlFlowForStatement.types create mode 100644 tests/baselines/reference/controlFlowIfStatement.js create mode 100644 tests/baselines/reference/controlFlowIfStatement.symbols create mode 100644 tests/baselines/reference/controlFlowIfStatement.types create mode 100644 tests/baselines/reference/controlFlowWhileStatement.js create mode 100644 tests/baselines/reference/controlFlowWhileStatement.symbols create mode 100644 tests/baselines/reference/controlFlowWhileStatement.types diff --git a/tests/baselines/reference/TypeGuardWithEnumUnion.types b/tests/baselines/reference/TypeGuardWithEnumUnion.types index 453ec220f02..05d55cb0dbb 100644 --- a/tests/baselines/reference/TypeGuardWithEnumUnion.types +++ b/tests/baselines/reference/TypeGuardWithEnumUnion.types @@ -55,7 +55,7 @@ function f2(x: Color | string | string[]) { if (typeof x === "number") { >typeof x === "number" : boolean >typeof x : string ->x : Color | string | string[] +>x : string[] | Color | string >"number" : string var z = x; @@ -68,16 +68,16 @@ function f2(x: Color | string | string[]) { } else { var w = x; ->w : string | string[] ->x : string | string[] +>w : string[] | string +>x : string[] | string var w: string | string[]; ->w : string | string[] +>w : string[] | string } if (typeof x === "string") { >typeof x === "string" : boolean >typeof x : string ->x : Color | string | string[] +>x : Color | string[] | string >"string" : string var a = x; diff --git a/tests/baselines/reference/controlFlowAssignmentExpression.js b/tests/baselines/reference/controlFlowAssignmentExpression.js new file mode 100644 index 00000000000..cf8d70b92de --- /dev/null +++ b/tests/baselines/reference/controlFlowAssignmentExpression.js @@ -0,0 +1,22 @@ +//// [controlFlowAssignmentExpression.ts] +let x: string | boolean | number; +let obj: any; + +x = ""; +x = x.length; +x; // number + +x = true; +(x = "", obj).foo = (x = x.length); +x; // number + + +//// [controlFlowAssignmentExpression.js] +var x; +var obj; +x = ""; +x = x.length; +x; // number +x = true; +(x = "", obj).foo = (x = x.length); +x; // number diff --git a/tests/baselines/reference/controlFlowAssignmentExpression.symbols b/tests/baselines/reference/controlFlowAssignmentExpression.symbols new file mode 100644 index 00000000000..470e3114ca8 --- /dev/null +++ b/tests/baselines/reference/controlFlowAssignmentExpression.symbols @@ -0,0 +1,33 @@ +=== tests/cases/conformance/controlFlow/controlFlowAssignmentExpression.ts === +let x: string | boolean | number; +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) + +let obj: any; +>obj : Symbol(obj, Decl(controlFlowAssignmentExpression.ts, 1, 3)) + +x = ""; +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) + +x = x.length; +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +x; // number +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) + +x = true; +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) + +(x = "", obj).foo = (x = x.length); +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) +>obj : Symbol(obj, Decl(controlFlowAssignmentExpression.ts, 1, 3)) +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +x; // number +>x : Symbol(x, Decl(controlFlowAssignmentExpression.ts, 0, 3)) + diff --git a/tests/baselines/reference/controlFlowAssignmentExpression.types b/tests/baselines/reference/controlFlowAssignmentExpression.types new file mode 100644 index 00000000000..24355fd8c4a --- /dev/null +++ b/tests/baselines/reference/controlFlowAssignmentExpression.types @@ -0,0 +1,47 @@ +=== tests/cases/conformance/controlFlow/controlFlowAssignmentExpression.ts === +let x: string | boolean | number; +>x : string | boolean | number + +let obj: any; +>obj : any + +x = ""; +>x = "" : string +>x : string | boolean | number +>"" : string + +x = x.length; +>x = x.length : number +>x : string | boolean | number +>x.length : number +>x : string +>length : number + +x; // number +>x : number + +x = true; +>x = true : boolean +>x : string | boolean | number +>true : boolean + +(x = "", obj).foo = (x = x.length); +>(x = "", obj).foo = (x = x.length) : number +>(x = "", obj).foo : any +>(x = "", obj) : any +>x = "", obj : any +>x = "" : string +>x : string | boolean | number +>"" : string +>obj : any +>foo : any +>(x = x.length) : number +>x = x.length : number +>x : string | boolean | number +>x.length : number +>x : string +>length : number + +x; // number +>x : number + diff --git a/tests/baselines/reference/controlFlowBinaryAndExpression.js b/tests/baselines/reference/controlFlowBinaryAndExpression.js new file mode 100644 index 00000000000..eb89d1a78cf --- /dev/null +++ b/tests/baselines/reference/controlFlowBinaryAndExpression.js @@ -0,0 +1,20 @@ +//// [controlFlowBinaryAndExpression.ts] +let x: string | number | boolean; +let cond: boolean; + +(x = "") && (x = 0); +x; // string | number + +x = ""; +cond && (x = 0); +x; // string | number + + +//// [controlFlowBinaryAndExpression.js] +var x; +var cond; +(x = "") && (x = 0); +x; // string | number +x = ""; +cond && (x = 0); +x; // string | number diff --git a/tests/baselines/reference/controlFlowBinaryAndExpression.symbols b/tests/baselines/reference/controlFlowBinaryAndExpression.symbols new file mode 100644 index 00000000000..5be553f6802 --- /dev/null +++ b/tests/baselines/reference/controlFlowBinaryAndExpression.symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/controlFlow/controlFlowBinaryAndExpression.ts === +let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowBinaryAndExpression.ts, 0, 3)) + +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowBinaryAndExpression.ts, 1, 3)) + +(x = "") && (x = 0); +>x : Symbol(x, Decl(controlFlowBinaryAndExpression.ts, 0, 3)) +>x : Symbol(x, Decl(controlFlowBinaryAndExpression.ts, 0, 3)) + +x; // string | number +>x : Symbol(x, Decl(controlFlowBinaryAndExpression.ts, 0, 3)) + +x = ""; +>x : Symbol(x, Decl(controlFlowBinaryAndExpression.ts, 0, 3)) + +cond && (x = 0); +>cond : Symbol(cond, Decl(controlFlowBinaryAndExpression.ts, 1, 3)) +>x : Symbol(x, Decl(controlFlowBinaryAndExpression.ts, 0, 3)) + +x; // string | number +>x : Symbol(x, Decl(controlFlowBinaryAndExpression.ts, 0, 3)) + diff --git a/tests/baselines/reference/controlFlowBinaryAndExpression.types b/tests/baselines/reference/controlFlowBinaryAndExpression.types new file mode 100644 index 00000000000..8a1924c42eb --- /dev/null +++ b/tests/baselines/reference/controlFlowBinaryAndExpression.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/controlFlow/controlFlowBinaryAndExpression.ts === +let x: string | number | boolean; +>x : string | number | boolean + +let cond: boolean; +>cond : boolean + +(x = "") && (x = 0); +>(x = "") && (x = 0) : number +>(x = "") : string +>x = "" : string +>x : string | number | boolean +>"" : string +>(x = 0) : number +>x = 0 : number +>x : string | number | boolean +>0 : number + +x; // string | number +>x : string | number + +x = ""; +>x = "" : string +>x : string | number | boolean +>"" : string + +cond && (x = 0); +>cond && (x = 0) : number +>cond : boolean +>(x = 0) : number +>x = 0 : number +>x : string | number | boolean +>0 : number + +x; // string | number +>x : string | number + diff --git a/tests/baselines/reference/controlFlowBinaryOrExpression.js b/tests/baselines/reference/controlFlowBinaryOrExpression.js new file mode 100644 index 00000000000..350e383a1f8 --- /dev/null +++ b/tests/baselines/reference/controlFlowBinaryOrExpression.js @@ -0,0 +1,20 @@ +//// [controlFlowBinaryOrExpression.ts] +let x: string | number | boolean; +let cond: boolean; + +(x = "") || (x = 0); +x; // string | number + +x = ""; +cond || (x = 0); +x; // string | number + + +//// [controlFlowBinaryOrExpression.js] +var x; +var cond; +(x = "") || (x = 0); +x; // string | number +x = ""; +cond || (x = 0); +x; // string | number diff --git a/tests/baselines/reference/controlFlowBinaryOrExpression.symbols b/tests/baselines/reference/controlFlowBinaryOrExpression.symbols new file mode 100644 index 00000000000..286612ef4df --- /dev/null +++ b/tests/baselines/reference/controlFlowBinaryOrExpression.symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts === +let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) + +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowBinaryOrExpression.ts, 1, 3)) + +(x = "") || (x = 0); +>x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) +>x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) + +x; // string | number +>x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) + +x = ""; +>x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) + +cond || (x = 0); +>cond : Symbol(cond, Decl(controlFlowBinaryOrExpression.ts, 1, 3)) +>x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) + +x; // string | number +>x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) + diff --git a/tests/baselines/reference/controlFlowBinaryOrExpression.types b/tests/baselines/reference/controlFlowBinaryOrExpression.types new file mode 100644 index 00000000000..404e153788a --- /dev/null +++ b/tests/baselines/reference/controlFlowBinaryOrExpression.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts === +let x: string | number | boolean; +>x : string | number | boolean + +let cond: boolean; +>cond : boolean + +(x = "") || (x = 0); +>(x = "") || (x = 0) : string | number +>(x = "") : string +>x = "" : string +>x : string | number | boolean +>"" : string +>(x = 0) : number +>x = 0 : number +>x : string | number | boolean +>0 : number + +x; // string | number +>x : string | number + +x = ""; +>x = "" : string +>x : string | number | boolean +>"" : string + +cond || (x = 0); +>cond || (x = 0) : boolean | number +>cond : boolean +>(x = 0) : number +>x = 0 : number +>x : string | number | boolean +>0 : number + +x; // string | number +>x : string | number + diff --git a/tests/baselines/reference/controlFlowConditionalExpression.js b/tests/baselines/reference/controlFlowConditionalExpression.js new file mode 100644 index 00000000000..f39b999039b --- /dev/null +++ b/tests/baselines/reference/controlFlowConditionalExpression.js @@ -0,0 +1,13 @@ +//// [controlFlowConditionalExpression.ts] +let x: string | number | boolean; +let cond: boolean; + +cond ? x = "" : x = 3; +x; // string | number + + +//// [controlFlowConditionalExpression.js] +var x; +var cond; +cond ? x = "" : x = 3; +x; // string | number diff --git a/tests/baselines/reference/controlFlowConditionalExpression.symbols b/tests/baselines/reference/controlFlowConditionalExpression.symbols new file mode 100644 index 00000000000..b1a4074d08d --- /dev/null +++ b/tests/baselines/reference/controlFlowConditionalExpression.symbols @@ -0,0 +1,15 @@ +=== tests/cases/conformance/controlFlow/controlFlowConditionalExpression.ts === +let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowConditionalExpression.ts, 0, 3)) + +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowConditionalExpression.ts, 1, 3)) + +cond ? x = "" : x = 3; +>cond : Symbol(cond, Decl(controlFlowConditionalExpression.ts, 1, 3)) +>x : Symbol(x, Decl(controlFlowConditionalExpression.ts, 0, 3)) +>x : Symbol(x, Decl(controlFlowConditionalExpression.ts, 0, 3)) + +x; // string | number +>x : Symbol(x, Decl(controlFlowConditionalExpression.ts, 0, 3)) + diff --git a/tests/baselines/reference/controlFlowConditionalExpression.types b/tests/baselines/reference/controlFlowConditionalExpression.types new file mode 100644 index 00000000000..c6084e052b1 --- /dev/null +++ b/tests/baselines/reference/controlFlowConditionalExpression.types @@ -0,0 +1,20 @@ +=== tests/cases/conformance/controlFlow/controlFlowConditionalExpression.ts === +let x: string | number | boolean; +>x : string | number | boolean + +let cond: boolean; +>cond : boolean + +cond ? x = "" : x = 3; +>cond ? x = "" : x = 3 : string | number +>cond : boolean +>x = "" : string +>x : string | number | boolean +>"" : string +>x = 3 : number +>x : string | number | boolean +>3 : number + +x; // string | number +>x : string | number + diff --git a/tests/baselines/reference/controlFlowDoWhileStatement.js b/tests/baselines/reference/controlFlowDoWhileStatement.js new file mode 100644 index 00000000000..635a5a59257 --- /dev/null +++ b/tests/baselines/reference/controlFlowDoWhileStatement.js @@ -0,0 +1,157 @@ +//// [controlFlowDoWhileStatement.ts] +let cond: boolean; +function a() { + let x: string | number; + x = ""; + do { + x; // string + } while (cond) +} +function b() { + let x: string | number; + x = ""; + do { + x; // string + x = 42; + break; + } while (cond) +} +function c() { + let x: string | number; + x = ""; + do { + x; // string + x = undefined; + if (typeof x === "string") continue; + break; + } while (cond) +} +function d() { + let x: string | number; + x = 1000; + do { + x; // number + x = ""; + } while (x = x.length) + x; // number +} +function e() { + let x: string | number; + x = ""; + do { + x = 42; + } while (cond) + x; // number +} +function f() { + let x: string | number | boolean | RegExp | Function; + x = ""; + do { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } while (cond) + x; // number | boolean | RegExp +} +function g() { + let x: string | number | boolean | RegExp | Function; + x = ""; + do { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } while (true) + x; // number +} + + +//// [controlFlowDoWhileStatement.js] +var cond; +function a() { + var x; + x = ""; + do { + x; // string + } while (cond); +} +function b() { + var x; + x = ""; + do { + x; // string + x = 42; + break; + } while (cond); +} +function c() { + var x; + x = ""; + do { + x; // string + x = undefined; + if (typeof x === "string") + continue; + break; + } while (cond); +} +function d() { + var x; + x = 1000; + do { + x; // number + x = ""; + } while (x = x.length); + x; // number +} +function e() { + var x; + x = ""; + do { + x = 42; + } while (cond); + x; // number +} +function f() { + var x; + x = ""; + do { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } while (cond); + x; // number | boolean | RegExp +} +function g() { + var x; + x = ""; + do { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } while (true); + x; // number +} diff --git a/tests/baselines/reference/controlFlowDoWhileStatement.symbols b/tests/baselines/reference/controlFlowDoWhileStatement.symbols new file mode 100644 index 00000000000..2a3f3858ec2 --- /dev/null +++ b/tests/baselines/reference/controlFlowDoWhileStatement.symbols @@ -0,0 +1,181 @@ +=== tests/cases/conformance/controlFlow/controlFlowDoWhileStatement.ts === +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) + +function a() { +>a : Symbol(a, Decl(controlFlowDoWhileStatement.ts, 0, 18)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 2, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 2, 7)) + + do { + x; // string +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 2, 7)) + + } while (cond) +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) +} +function b() { +>b : Symbol(b, Decl(controlFlowDoWhileStatement.ts, 7, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 9, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 9, 7)) + + do { + x; // string +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 9, 7)) + + x = 42; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 9, 7)) + + break; + } while (cond) +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) +} +function c() { +>c : Symbol(c, Decl(controlFlowDoWhileStatement.ts, 16, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 18, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 18, 7)) + + do { + x; // string +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 18, 7)) + + x = undefined; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 18, 7)) +>undefined : Symbol(undefined) + + if (typeof x === "string") continue; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 18, 7)) + + break; + } while (cond) +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) +} +function d() { +>d : Symbol(d, Decl(controlFlowDoWhileStatement.ts, 26, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 28, 7)) + + x = 1000; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 28, 7)) + + do { + x; // number +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 28, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 28, 7)) + + } while (x = x.length) +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 28, 7)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 28, 7)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + + x; // number +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 28, 7)) +} +function e() { +>e : Symbol(e, Decl(controlFlowDoWhileStatement.ts, 35, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 37, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 37, 7)) + + do { + x = 42; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 37, 7)) + + } while (cond) +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) + + x; // number +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 37, 7)) +} +function f() { +>f : Symbol(f, Decl(controlFlowDoWhileStatement.ts, 43, 1)) + + let x: string | number | boolean | RegExp | Function; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 45, 7)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + x = ""; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 45, 7)) + + do { + if (cond) { +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 45, 7)) + + break; + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) + + x = true; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 45, 7)) + + continue; + } + x = /a/; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 45, 7)) + + } while (cond) +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) + + x; // number | boolean | RegExp +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 45, 7)) +} +function g() { +>g : Symbol(g, Decl(controlFlowDoWhileStatement.ts, 59, 1)) + + let x: string | number | boolean | RegExp | Function; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 61, 7)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + x = ""; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 61, 7)) + + do { + if (cond) { +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 61, 7)) + + break; + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowDoWhileStatement.ts, 0, 3)) + + x = true; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 61, 7)) + + continue; + } + x = /a/; +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 61, 7)) + + } while (true) + x; // number +>x : Symbol(x, Decl(controlFlowDoWhileStatement.ts, 61, 7)) +} + diff --git a/tests/baselines/reference/controlFlowDoWhileStatement.types b/tests/baselines/reference/controlFlowDoWhileStatement.types new file mode 100644 index 00000000000..a82ae1b716e --- /dev/null +++ b/tests/baselines/reference/controlFlowDoWhileStatement.types @@ -0,0 +1,220 @@ +=== tests/cases/conformance/controlFlow/controlFlowDoWhileStatement.ts === +let cond: boolean; +>cond : boolean + +function a() { +>a : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + do { + x; // string +>x : string + + } while (cond) +>cond : boolean +} +function b() { +>b : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + do { + x; // string +>x : string + + x = 42; +>x = 42 : number +>x : string | number +>42 : number + + break; + } while (cond) +>cond : boolean +} +function c() { +>c : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + do { + x; // string +>x : string + + x = undefined; +>x = undefined : undefined +>x : string | number +>undefined : undefined + + if (typeof x === "string") continue; +>typeof x === "string" : boolean +>typeof x : string +>x : string | number +>"string" : string + + break; + } while (cond) +>cond : boolean +} +function d() { +>d : () => void + + let x: string | number; +>x : string | number + + x = 1000; +>x = 1000 : number +>x : string | number +>1000 : number + + do { + x; // number +>x : number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + } while (x = x.length) +>x = x.length : number +>x : string | number +>x.length : number +>x : string +>length : number + + x; // number +>x : number +} +function e() { +>e : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + do { + x = 42; +>x = 42 : number +>x : string | number +>42 : number + + } while (cond) +>cond : boolean + + x; // number +>x : number +} +function f() { +>f : () => void + + let x: string | number | boolean | RegExp | Function; +>x : string | number | boolean | RegExp | Function +>RegExp : RegExp +>Function : Function + + x = ""; +>x = "" : string +>x : string | number | boolean | RegExp | Function +>"" : string + + do { + if (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number | boolean | RegExp | Function +>42 : number + + break; + } + if (cond) { +>cond : boolean + + x = true; +>x = true : boolean +>x : string | number | boolean | RegExp | Function +>true : boolean + + continue; + } + x = /a/; +>x = /a/ : RegExp +>x : string | number | boolean | RegExp | Function +>/a/ : RegExp + + } while (cond) +>cond : boolean + + x; // number | boolean | RegExp +>x : number | boolean | RegExp +} +function g() { +>g : () => void + + let x: string | number | boolean | RegExp | Function; +>x : string | number | boolean | RegExp | Function +>RegExp : RegExp +>Function : Function + + x = ""; +>x = "" : string +>x : string | number | boolean | RegExp | Function +>"" : string + + do { + if (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number | boolean | RegExp | Function +>42 : number + + break; + } + if (cond) { +>cond : boolean + + x = true; +>x = true : boolean +>x : string | number | boolean | RegExp | Function +>true : boolean + + continue; + } + x = /a/; +>x = /a/ : RegExp +>x : string | number | boolean | RegExp | Function +>/a/ : RegExp + + } while (true) +>true : boolean + + x; // number +>x : number +} + diff --git a/tests/baselines/reference/controlFlowForInStatement.js b/tests/baselines/reference/controlFlowForInStatement.js new file mode 100644 index 00000000000..1d3f29de2ad --- /dev/null +++ b/tests/baselines/reference/controlFlowForInStatement.js @@ -0,0 +1,37 @@ +//// [controlFlowForInStatement.ts] +let x: string | number | boolean | RegExp | Function; +let obj: any; +let cond: boolean; + +x = /a/; +for (let y in obj) { + x = y; + if (cond) { + x = 42; + continue; + } + if (cond) { + x = true; + break; + } +} +x; // RegExp | string | number | boolean + + +//// [controlFlowForInStatement.js] +var x; +var obj; +var cond; +x = /a/; +for (var y in obj) { + x = y; + if (cond) { + x = 42; + continue; + } + if (cond) { + x = true; + break; + } +} +x; // RegExp | string | number | boolean diff --git a/tests/baselines/reference/controlFlowForInStatement.symbols b/tests/baselines/reference/controlFlowForInStatement.symbols new file mode 100644 index 00000000000..8d01ff50193 --- /dev/null +++ b/tests/baselines/reference/controlFlowForInStatement.symbols @@ -0,0 +1,43 @@ +=== tests/cases/conformance/controlFlow/controlFlowForInStatement.ts === +let x: string | number | boolean | RegExp | Function; +>x : Symbol(x, Decl(controlFlowForInStatement.ts, 0, 3)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +let obj: any; +>obj : Symbol(obj, Decl(controlFlowForInStatement.ts, 1, 3)) + +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowForInStatement.ts, 2, 3)) + +x = /a/; +>x : Symbol(x, Decl(controlFlowForInStatement.ts, 0, 3)) + +for (let y in obj) { +>y : Symbol(y, Decl(controlFlowForInStatement.ts, 5, 8)) +>obj : Symbol(obj, Decl(controlFlowForInStatement.ts, 1, 3)) + + x = y; +>x : Symbol(x, Decl(controlFlowForInStatement.ts, 0, 3)) +>y : Symbol(y, Decl(controlFlowForInStatement.ts, 5, 8)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowForInStatement.ts, 2, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowForInStatement.ts, 0, 3)) + + continue; + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowForInStatement.ts, 2, 3)) + + x = true; +>x : Symbol(x, Decl(controlFlowForInStatement.ts, 0, 3)) + + break; + } +} +x; // RegExp | string | number | boolean +>x : Symbol(x, Decl(controlFlowForInStatement.ts, 0, 3)) + diff --git a/tests/baselines/reference/controlFlowForInStatement.types b/tests/baselines/reference/controlFlowForInStatement.types new file mode 100644 index 00000000000..e46db37bb16 --- /dev/null +++ b/tests/baselines/reference/controlFlowForInStatement.types @@ -0,0 +1,50 @@ +=== tests/cases/conformance/controlFlow/controlFlowForInStatement.ts === +let x: string | number | boolean | RegExp | Function; +>x : string | number | boolean | RegExp | Function +>RegExp : RegExp +>Function : Function + +let obj: any; +>obj : any + +let cond: boolean; +>cond : boolean + +x = /a/; +>x = /a/ : RegExp +>x : string | number | boolean | RegExp | Function +>/a/ : RegExp + +for (let y in obj) { +>y : string +>obj : any + + x = y; +>x = y : string +>x : string | number | boolean | RegExp | Function +>y : string + + if (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number | boolean | RegExp | Function +>42 : number + + continue; + } + if (cond) { +>cond : boolean + + x = true; +>x = true : boolean +>x : string | number | boolean | RegExp | Function +>true : boolean + + break; + } +} +x; // RegExp | string | number | boolean +>x : RegExp | number | string | boolean + diff --git a/tests/baselines/reference/controlFlowForOfStatement.js b/tests/baselines/reference/controlFlowForOfStatement.js new file mode 100644 index 00000000000..31ba7f1a346 --- /dev/null +++ b/tests/baselines/reference/controlFlowForOfStatement.js @@ -0,0 +1,24 @@ +//// [controlFlowForOfStatement.ts] +let obj: number[]; +let x: string | number | boolean | RegExp; + +function a() { + x = true; + for (x of obj) { + x = x.toExponential(); + } + x; // string | boolean +} + + +//// [controlFlowForOfStatement.js] +var obj; +var x; +function a() { + x = true; + for (var _i = 0, obj_1 = obj; _i < obj_1.length; _i++) { + x = obj_1[_i]; + x = x.toExponential(); + } + x; // string | boolean +} diff --git a/tests/baselines/reference/controlFlowForOfStatement.symbols b/tests/baselines/reference/controlFlowForOfStatement.symbols new file mode 100644 index 00000000000..0f1e754be41 --- /dev/null +++ b/tests/baselines/reference/controlFlowForOfStatement.symbols @@ -0,0 +1,28 @@ +=== tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts === +let obj: number[]; +>obj : Symbol(obj, Decl(controlFlowForOfStatement.ts, 0, 3)) + +let x: string | number | boolean | RegExp; +>x : Symbol(x, Decl(controlFlowForOfStatement.ts, 1, 3)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +function a() { +>a : Symbol(a, Decl(controlFlowForOfStatement.ts, 1, 42)) + + x = true; +>x : Symbol(x, Decl(controlFlowForOfStatement.ts, 1, 3)) + + for (x of obj) { +>x : Symbol(x, Decl(controlFlowForOfStatement.ts, 1, 3)) +>obj : Symbol(obj, Decl(controlFlowForOfStatement.ts, 0, 3)) + + x = x.toExponential(); +>x : Symbol(x, Decl(controlFlowForOfStatement.ts, 1, 3)) +>x.toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowForOfStatement.ts, 1, 3)) +>toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) + } + x; // string | boolean +>x : Symbol(x, Decl(controlFlowForOfStatement.ts, 1, 3)) +} + diff --git a/tests/baselines/reference/controlFlowForOfStatement.types b/tests/baselines/reference/controlFlowForOfStatement.types new file mode 100644 index 00000000000..437576e51b6 --- /dev/null +++ b/tests/baselines/reference/controlFlowForOfStatement.types @@ -0,0 +1,32 @@ +=== tests/cases/conformance/controlFlow/controlFlowForOfStatement.ts === +let obj: number[]; +>obj : number[] + +let x: string | number | boolean | RegExp; +>x : string | number | boolean | RegExp +>RegExp : RegExp + +function a() { +>a : () => void + + x = true; +>x = true : boolean +>x : string | number | boolean | RegExp +>true : boolean + + for (x of obj) { +>x : string | number | boolean | RegExp +>obj : number[] + + x = x.toExponential(); +>x = x.toExponential() : string +>x : string | number | boolean | RegExp +>x.toExponential() : string +>x.toExponential : (fractionDigits?: number) => string +>x : number +>toExponential : (fractionDigits?: number) => string + } + x; // string | boolean +>x : boolean | string +} + diff --git a/tests/baselines/reference/controlFlowForStatement.js b/tests/baselines/reference/controlFlowForStatement.js new file mode 100644 index 00000000000..d9b1d0814fe --- /dev/null +++ b/tests/baselines/reference/controlFlowForStatement.js @@ -0,0 +1,87 @@ +//// [controlFlowForStatement.ts] +let cond: boolean; +function a() { + let x: string | number | boolean; + for (x = ""; cond; x = 5) { + x; // string | number + } +} +function b() { + let x: string | number | boolean; + for (x = 5; cond; x = x.length) { + x; // number + x = ""; + } +} +function c() { + let x: string | number | boolean; + for (x = 5; x = x.toExponential(); x = 5) { + x; // string + } +} +function d() { + let x: string | number | boolean; + for (x = ""; typeof x === "string"; x = 5) { + x; // string + } +} +function e() { + let x: string | number | boolean | RegExp; + for (x = "" || 0; typeof x !== "string"; x = "" || true) { + x; // number | boolean + } +} +function f() { + let x: string | number | boolean; + for (; typeof x !== "string";) { + x; // number | boolean + if (typeof x === "number") break; + x = undefined; + } + x; // string | number +} + + +//// [controlFlowForStatement.js] +var cond; +function a() { + var x; + for (x = ""; cond; x = 5) { + x; // string | number + } +} +function b() { + var x; + for (x = 5; cond; x = x.length) { + x; // number + x = ""; + } +} +function c() { + var x; + for (x = 5; x = x.toExponential(); x = 5) { + x; // string + } +} +function d() { + var x; + for (x = ""; typeof x === "string"; x = 5) { + x; // string + } +} +function e() { + var x; + for (x = "" || 0; typeof x !== "string"; x = "" || true) { + x; // number | boolean + } +} +function f() { + var x; + for (; typeof x !== "string";) { + x; // number | boolean + if (typeof x === "number") + break; + x = undefined; + } + x; // string | number +} diff --git a/tests/baselines/reference/controlFlowForStatement.symbols b/tests/baselines/reference/controlFlowForStatement.symbols new file mode 100644 index 00000000000..1918fe0ca33 --- /dev/null +++ b/tests/baselines/reference/controlFlowForStatement.symbols @@ -0,0 +1,112 @@ +=== tests/cases/conformance/controlFlow/controlFlowForStatement.ts === +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowForStatement.ts, 0, 3)) + +function a() { +>a : Symbol(a, Decl(controlFlowForStatement.ts, 0, 18)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 2, 7)) + + for (x = ""; cond; x = 5) { +>x : Symbol(x, Decl(controlFlowForStatement.ts, 2, 7)) +>cond : Symbol(cond, Decl(controlFlowForStatement.ts, 0, 3)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 2, 7)) + + x; // string | number +>x : Symbol(x, Decl(controlFlowForStatement.ts, 2, 7)) + } +} +function b() { +>b : Symbol(b, Decl(controlFlowForStatement.ts, 6, 1)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 8, 7)) + + for (x = 5; cond; x = x.length) { +>x : Symbol(x, Decl(controlFlowForStatement.ts, 8, 7)) +>cond : Symbol(cond, Decl(controlFlowForStatement.ts, 0, 3)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 8, 7)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 8, 7)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + + x; // number +>x : Symbol(x, Decl(controlFlowForStatement.ts, 8, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 8, 7)) + } +} +function c() { +>c : Symbol(c, Decl(controlFlowForStatement.ts, 13, 1)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 15, 7)) + + for (x = 5; x = x.toExponential(); x = 5) { +>x : Symbol(x, Decl(controlFlowForStatement.ts, 15, 7)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 15, 7)) +>x.toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 15, 7)) +>toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 15, 7)) + + x; // string +>x : Symbol(x, Decl(controlFlowForStatement.ts, 15, 7)) + } +} +function d() { +>d : Symbol(d, Decl(controlFlowForStatement.ts, 19, 1)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 21, 7)) + + for (x = ""; typeof x === "string"; x = 5) { +>x : Symbol(x, Decl(controlFlowForStatement.ts, 21, 7)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 21, 7)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 21, 7)) + + x; // string +>x : Symbol(x, Decl(controlFlowForStatement.ts, 21, 7)) + } +} +function e() { +>e : Symbol(e, Decl(controlFlowForStatement.ts, 25, 1)) + + let x: string | number | boolean | RegExp; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 27, 7)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + for (x = "" || 0; typeof x !== "string"; x = "" || true) { +>x : Symbol(x, Decl(controlFlowForStatement.ts, 27, 7)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 27, 7)) +>x : Symbol(x, Decl(controlFlowForStatement.ts, 27, 7)) + + x; // number | boolean +>x : Symbol(x, Decl(controlFlowForStatement.ts, 27, 7)) + } +} +function f() { +>f : Symbol(f, Decl(controlFlowForStatement.ts, 31, 1)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 33, 7)) + + for (; typeof x !== "string";) { +>x : Symbol(x, Decl(controlFlowForStatement.ts, 33, 7)) + + x; // number | boolean +>x : Symbol(x, Decl(controlFlowForStatement.ts, 33, 7)) + + if (typeof x === "number") break; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 33, 7)) + + x = undefined; +>x : Symbol(x, Decl(controlFlowForStatement.ts, 33, 7)) +>undefined : Symbol(undefined) + } + x; // string | number +>x : Symbol(x, Decl(controlFlowForStatement.ts, 33, 7)) +} + diff --git a/tests/baselines/reference/controlFlowForStatement.types b/tests/baselines/reference/controlFlowForStatement.types new file mode 100644 index 00000000000..cdf049b32d6 --- /dev/null +++ b/tests/baselines/reference/controlFlowForStatement.types @@ -0,0 +1,152 @@ +=== tests/cases/conformance/controlFlow/controlFlowForStatement.ts === +let cond: boolean; +>cond : boolean + +function a() { +>a : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + for (x = ""; cond; x = 5) { +>x = "" : string +>x : string | number | boolean +>"" : string +>cond : boolean +>x = 5 : number +>x : string | number | boolean +>5 : number + + x; // string | number +>x : string | number + } +} +function b() { +>b : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + for (x = 5; cond; x = x.length) { +>x = 5 : number +>x : string | number | boolean +>5 : number +>cond : boolean +>x = x.length : number +>x : string | number | boolean +>x.length : number +>x : string +>length : number + + x; // number +>x : number + + x = ""; +>x = "" : string +>x : string | number | boolean +>"" : string + } +} +function c() { +>c : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + for (x = 5; x = x.toExponential(); x = 5) { +>x = 5 : number +>x : string | number | boolean +>5 : number +>x = x.toExponential() : string +>x : string | number | boolean +>x.toExponential() : string +>x.toExponential : (fractionDigits?: number) => string +>x : number +>toExponential : (fractionDigits?: number) => string +>x = 5 : number +>x : string | number | boolean +>5 : number + + x; // string +>x : string + } +} +function d() { +>d : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + for (x = ""; typeof x === "string"; x = 5) { +>x = "" : string +>x : string | number | boolean +>"" : string +>typeof x === "string" : boolean +>typeof x : string +>x : string | number +>"string" : string +>x = 5 : number +>x : string | number | boolean +>5 : number + + x; // string +>x : string + } +} +function e() { +>e : () => void + + let x: string | number | boolean | RegExp; +>x : string | number | boolean | RegExp +>RegExp : RegExp + + for (x = "" || 0; typeof x !== "string"; x = "" || true) { +>x = "" || 0 : string | number +>x : string | number | boolean | RegExp +>"" || 0 : string | number +>"" : string +>0 : number +>typeof x !== "string" : boolean +>typeof x : string +>x : string | number | boolean +>"string" : string +>x = "" || true : string | boolean +>x : string | number | boolean | RegExp +>"" || true : string | boolean +>"" : string +>true : boolean + + x; // number | boolean +>x : number | boolean + } +} +function f() { +>f : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + for (; typeof x !== "string";) { +>typeof x !== "string" : boolean +>typeof x : string +>x : string | number | boolean +>"string" : string + + x; // number | boolean +>x : number | boolean + + if (typeof x === "number") break; +>typeof x === "number" : boolean +>typeof x : string +>x : number | boolean +>"number" : string + + x = undefined; +>x = undefined : undefined +>x : string | number | boolean +>undefined : undefined + } + x; // string | number +>x : string | number +} + diff --git a/tests/baselines/reference/controlFlowIfStatement.js b/tests/baselines/reference/controlFlowIfStatement.js new file mode 100644 index 00000000000..a70c07d38dc --- /dev/null +++ b/tests/baselines/reference/controlFlowIfStatement.js @@ -0,0 +1,74 @@ +//// [controlFlowIfStatement.ts] +let x: string | number | boolean | RegExp; +let cond: boolean; + +x = /a/; +if (x /* RegExp */, (x = true)) { + x; // boolean + x = ""; +} +else { + x; // boolean + x = 42; +} +x; // string | number + +function a() { + let x: string | number; + if (cond) { + x = 42; + } + else { + x = ""; + return; + } + x; // number +} +function b() { + let x: string | number; + if (cond) { + x = 42; + throw ""; + } + else { + x = ""; + } + x; // string +} + + +//// [controlFlowIfStatement.js] +var x; +var cond; +x = /a/; +if (x /* RegExp */, (x = true)) { + x; // boolean + x = ""; +} +else { + x; // boolean + x = 42; +} +x; // string | number +function a() { + var x; + if (cond) { + x = 42; + } + else { + x = ""; + return; + } + x; // number +} +function b() { + var x; + if (cond) { + x = 42; + throw ""; + } + else { + x = ""; + } + x; // string +} diff --git a/tests/baselines/reference/controlFlowIfStatement.symbols b/tests/baselines/reference/controlFlowIfStatement.symbols new file mode 100644 index 00000000000..1d85b31c998 --- /dev/null +++ b/tests/baselines/reference/controlFlowIfStatement.symbols @@ -0,0 +1,74 @@ +=== tests/cases/conformance/controlFlow/controlFlowIfStatement.ts === +let x: string | number | boolean | RegExp; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowIfStatement.ts, 1, 3)) + +x = /a/; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) + +if (x /* RegExp */, (x = true)) { +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) + + x; // boolean +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) + + x = ""; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) +} +else { + x; // boolean +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) +} +x; // string | number +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 0, 3)) + +function a() { +>a : Symbol(a, Decl(controlFlowIfStatement.ts, 12, 2)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 15, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowIfStatement.ts, 1, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 15, 7)) + } + else { + x = ""; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 15, 7)) + + return; + } + x; // number +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 15, 7)) +} +function b() { +>b : Symbol(b, Decl(controlFlowIfStatement.ts, 24, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 26, 7)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowIfStatement.ts, 1, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 26, 7)) + + throw ""; + } + else { + x = ""; +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 26, 7)) + } + x; // string +>x : Symbol(x, Decl(controlFlowIfStatement.ts, 26, 7)) +} + diff --git a/tests/baselines/reference/controlFlowIfStatement.types b/tests/baselines/reference/controlFlowIfStatement.types new file mode 100644 index 00000000000..dc07e23275f --- /dev/null +++ b/tests/baselines/reference/controlFlowIfStatement.types @@ -0,0 +1,93 @@ +=== tests/cases/conformance/controlFlow/controlFlowIfStatement.ts === +let x: string | number | boolean | RegExp; +>x : string | number | boolean | RegExp +>RegExp : RegExp + +let cond: boolean; +>cond : boolean + +x = /a/; +>x = /a/ : RegExp +>x : string | number | boolean | RegExp +>/a/ : RegExp + +if (x /* RegExp */, (x = true)) { +>x /* RegExp */, (x = true) : boolean +>x : RegExp +>(x = true) : boolean +>x = true : boolean +>x : string | number | boolean | RegExp +>true : boolean + + x; // boolean +>x : boolean + + x = ""; +>x = "" : string +>x : string | number | boolean | RegExp +>"" : string +} +else { + x; // boolean +>x : boolean + + x = 42; +>x = 42 : number +>x : string | number | boolean | RegExp +>42 : number +} +x; // string | number +>x : string | number + +function a() { +>a : () => void + + let x: string | number; +>x : string | number + + if (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number +>42 : number + } + else { + x = ""; +>x = "" : string +>x : string | number +>"" : string + + return; + } + x; // number +>x : number +} +function b() { +>b : () => void + + let x: string | number; +>x : string | number + + if (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number +>42 : number + + throw ""; +>"" : string + } + else { + x = ""; +>x = "" : string +>x : string | number +>"" : string + } + x; // string +>x : string +} + diff --git a/tests/baselines/reference/controlFlowWhileStatement.js b/tests/baselines/reference/controlFlowWhileStatement.js new file mode 100644 index 00000000000..fc975764ce1 --- /dev/null +++ b/tests/baselines/reference/controlFlowWhileStatement.js @@ -0,0 +1,155 @@ +//// [controlFlowWhileStatement.ts] +let cond: boolean; +function a() { + let x: string | number; + x = ""; + while (cond) { + x; // string + } +} +function b() { + let x: string | number; + x = ""; + while (cond) { + x; // string + x = 42; + break; + } +} +function c() { + let x: string | number; + x = ""; + while (cond) { + x; // string + x = undefined; + if (typeof x === "string") continue; + break; + } +} +function d() { + let x: string | number; + x = ""; + while (x = x.length) { + x; // number + x = ""; + } +} +function e() { + let x: string | number; + x = ""; + while (cond) { + x = 42; + } + x; // string | number +} +function f() { + let x: string | number | boolean | RegExp | Function; + x = ""; + while (cond) { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } + x; // string | number | boolean | RegExp +} +function g() { + let x: string | number | boolean | RegExp | Function; + x = ""; + while (true) { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } + x; // number +} + + +//// [controlFlowWhileStatement.js] +var cond; +function a() { + var x; + x = ""; + while (cond) { + x; // string + } +} +function b() { + var x; + x = ""; + while (cond) { + x; // string + x = 42; + break; + } +} +function c() { + var x; + x = ""; + while (cond) { + x; // string + x = undefined; + if (typeof x === "string") + continue; + break; + } +} +function d() { + var x; + x = ""; + while (x = x.length) { + x; // number + x = ""; + } +} +function e() { + var x; + x = ""; + while (cond) { + x = 42; + } + x; // string | number +} +function f() { + var x; + x = ""; + while (cond) { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } + x; // string | number | boolean | RegExp +} +function g() { + var x; + x = ""; + while (true) { + if (cond) { + x = 42; + break; + } + if (cond) { + x = true; + continue; + } + x = /a/; + } + x; // number +} diff --git a/tests/baselines/reference/controlFlowWhileStatement.symbols b/tests/baselines/reference/controlFlowWhileStatement.symbols new file mode 100644 index 00000000000..27e1b533d14 --- /dev/null +++ b/tests/baselines/reference/controlFlowWhileStatement.symbols @@ -0,0 +1,177 @@ +=== tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts === +let cond: boolean; +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + +function a() { +>a : Symbol(a, Decl(controlFlowWhileStatement.ts, 0, 18)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 2, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 2, 7)) + + while (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x; // string +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 2, 7)) + } +} +function b() { +>b : Symbol(b, Decl(controlFlowWhileStatement.ts, 7, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 9, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 9, 7)) + + while (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x; // string +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 9, 7)) + + x = 42; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 9, 7)) + + break; + } +} +function c() { +>c : Symbol(c, Decl(controlFlowWhileStatement.ts, 16, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 18, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 18, 7)) + + while (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x; // string +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 18, 7)) + + x = undefined; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 18, 7)) +>undefined : Symbol(undefined) + + if (typeof x === "string") continue; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 18, 7)) + + break; + } +} +function d() { +>d : Symbol(d, Decl(controlFlowWhileStatement.ts, 26, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 28, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 28, 7)) + + while (x = x.length) { +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 28, 7)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 28, 7)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + + x; // number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 28, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 28, 7)) + } +} +function e() { +>e : Symbol(e, Decl(controlFlowWhileStatement.ts, 34, 1)) + + let x: string | number; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) + + while (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) + } + x; // string | number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) +} +function f() { +>f : Symbol(f, Decl(controlFlowWhileStatement.ts, 42, 1)) + + let x: string | number | boolean | RegExp | Function; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) + + while (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + if (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) + + break; + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x = true; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) + + continue; + } + x = /a/; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) + } + x; // string | number | boolean | RegExp +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +} +function g() { +>g : Symbol(g, Decl(controlFlowWhileStatement.ts, 58, 1)) + + let x: string | number | boolean | RegExp | Function; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) + + while (true) { + if (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x = 42; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) + + break; + } + if (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x = true; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) + + continue; + } + x = /a/; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) + } + x; // number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +} + diff --git a/tests/baselines/reference/controlFlowWhileStatement.types b/tests/baselines/reference/controlFlowWhileStatement.types new file mode 100644 index 00000000000..7c99b152048 --- /dev/null +++ b/tests/baselines/reference/controlFlowWhileStatement.types @@ -0,0 +1,216 @@ +=== tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts === +let cond: boolean; +>cond : boolean + +function a() { +>a : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + while (cond) { +>cond : boolean + + x; // string +>x : string + } +} +function b() { +>b : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + while (cond) { +>cond : boolean + + x; // string +>x : string + + x = 42; +>x = 42 : number +>x : string | number +>42 : number + + break; + } +} +function c() { +>c : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + while (cond) { +>cond : boolean + + x; // string +>x : string + + x = undefined; +>x = undefined : undefined +>x : string | number +>undefined : undefined + + if (typeof x === "string") continue; +>typeof x === "string" : boolean +>typeof x : string +>x : string | number +>"string" : string + + break; + } +} +function d() { +>d : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + while (x = x.length) { +>x = x.length : number +>x : string | number +>x.length : number +>x : string +>length : number + + x; // number +>x : number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + } +} +function e() { +>e : () => void + + let x: string | number; +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + while (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number +>42 : number + } + x; // string | number +>x : string | number +} +function f() { +>f : () => void + + let x: string | number | boolean | RegExp | Function; +>x : string | number | boolean | RegExp | Function +>RegExp : RegExp +>Function : Function + + x = ""; +>x = "" : string +>x : string | number | boolean | RegExp | Function +>"" : string + + while (cond) { +>cond : boolean + + if (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number | boolean | RegExp | Function +>42 : number + + break; + } + if (cond) { +>cond : boolean + + x = true; +>x = true : boolean +>x : string | number | boolean | RegExp | Function +>true : boolean + + continue; + } + x = /a/; +>x = /a/ : RegExp +>x : string | number | boolean | RegExp | Function +>/a/ : RegExp + } + x; // string | number | boolean | RegExp +>x : string | boolean | RegExp | number +} +function g() { +>g : () => void + + let x: string | number | boolean | RegExp | Function; +>x : string | number | boolean | RegExp | Function +>RegExp : RegExp +>Function : Function + + x = ""; +>x = "" : string +>x : string | number | boolean | RegExp | Function +>"" : string + + while (true) { +>true : boolean + + if (cond) { +>cond : boolean + + x = 42; +>x = 42 : number +>x : string | number | boolean | RegExp | Function +>42 : number + + break; + } + if (cond) { +>cond : boolean + + x = true; +>x = true : boolean +>x : string | number | boolean | RegExp | Function +>true : boolean + + continue; + } + x = /a/; +>x = /a/ : RegExp +>x : string | number | boolean | RegExp | Function +>/a/ : RegExp + } + x; // number +>x : number +} + diff --git a/tests/baselines/reference/for-of45.types b/tests/baselines/reference/for-of45.types index b71e062eccf..7c853993b0a 100644 --- a/tests/baselines/reference/for-of45.types +++ b/tests/baselines/reference/for-of45.types @@ -13,7 +13,7 @@ var map = new Map([["", true]]); >true : boolean for ([k = "", v = false] of map) { ->[k = "", v = false] : (string | boolean)[] +>[k = "", v = false] : [string, boolean] >k = "" : string >k : string >"" : string diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types index 33b503d0d8f..78cb778b545 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPattern2.types @@ -93,7 +93,7 @@ let numberA3: number, robotAInfo: (number | string)[], multiRobotAInfo: (string >multiRobotAInfo : (string | [string, string])[] for ([, nameA] of robots) { ->[, nameA] : string[] +>[, nameA] : [undefined, string] > : undefined >nameA : string >robots : [number, string, string][] @@ -106,7 +106,7 @@ for ([, nameA] of robots) { >nameA : string } for ([, nameA] of getRobots()) { ->[, nameA] : string[] +>[, nameA] : [undefined, string] > : undefined >nameA : string >getRobots() : [number, string, string][] @@ -120,7 +120,7 @@ for ([, nameA] of getRobots()) { >nameA : string } for ([, nameA] of [robotA, robotB]) { ->[, nameA] : string[] +>[, nameA] : [undefined, string] > : undefined >nameA : string >[robotA, robotB] : [number, string, string][] @@ -135,9 +135,9 @@ for ([, nameA] of [robotA, robotB]) { >nameA : string } for ([, [primarySkillA, secondarySkillA]] of multiRobots) { ->[, [primarySkillA, secondarySkillA]] : string[][] +>[, [primarySkillA, secondarySkillA]] : [undefined, [string, string]] > : undefined ->[primarySkillA, secondarySkillA] : string[] +>[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string >multiRobots : [string, [string, string]][] @@ -150,9 +150,9 @@ for ([, [primarySkillA, secondarySkillA]] of multiRobots) { >primarySkillA : string } for ([, [primarySkillA, secondarySkillA]] of getMultiRobots()) { ->[, [primarySkillA, secondarySkillA]] : string[][] +>[, [primarySkillA, secondarySkillA]] : [undefined, [string, string]] > : undefined ->[primarySkillA, secondarySkillA] : string[] +>[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string >getMultiRobots() : [string, [string, string]][] @@ -166,9 +166,9 @@ for ([, [primarySkillA, secondarySkillA]] of getMultiRobots()) { >primarySkillA : string } for ([, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { ->[, [primarySkillA, secondarySkillA]] : string[][] +>[, [primarySkillA, secondarySkillA]] : [undefined, [string, string]] > : undefined ->[primarySkillA, secondarySkillA] : string[] +>[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string >[multiRobotA, multiRobotB] : [string, [string, string]][] @@ -184,7 +184,7 @@ for ([, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { } for ([numberB] of robots) { ->[numberB] : number[] +>[numberB] : [number] >numberB : number >robots : [number, string, string][] @@ -196,7 +196,7 @@ for ([numberB] of robots) { >numberB : number } for ([numberB] of getRobots()) { ->[numberB] : number[] +>[numberB] : [number] >numberB : number >getRobots() : [number, string, string][] >getRobots : () => [number, string, string][] @@ -209,7 +209,7 @@ for ([numberB] of getRobots()) { >numberB : number } for ([numberB] of [robotA, robotB]) { ->[numberB] : number[] +>[numberB] : [number] >numberB : number >[robotA, robotB] : [number, string, string][] >robotA : [number, string, string] @@ -223,7 +223,7 @@ for ([numberB] of [robotA, robotB]) { >numberB : number } for ([nameB] of multiRobots) { ->[nameB] : string[] +>[nameB] : [string] >nameB : string >multiRobots : [string, [string, string]][] @@ -235,7 +235,7 @@ for ([nameB] of multiRobots) { >nameB : string } for ([nameB] of getMultiRobots()) { ->[nameB] : string[] +>[nameB] : [string] >nameB : string >getMultiRobots() : [string, [string, string]][] >getMultiRobots : () => [string, [string, string]][] @@ -248,7 +248,7 @@ for ([nameB] of getMultiRobots()) { >nameB : string } for ([nameB] of [multiRobotA, multiRobotB]) { ->[nameB] : string[] +>[nameB] : [string] >nameB : string >[multiRobotA, multiRobotB] : [string, [string, string]][] >multiRobotA : [string, [string, string]] @@ -263,7 +263,7 @@ for ([nameB] of [multiRobotA, multiRobotB]) { } for ([numberA2, nameA2, skillA2] of robots) { ->[numberA2, nameA2, skillA2] : (number | string)[] +>[numberA2, nameA2, skillA2] : [number, string, string] >numberA2 : number >nameA2 : string >skillA2 : string @@ -277,7 +277,7 @@ for ([numberA2, nameA2, skillA2] of robots) { >nameA2 : string } for ([numberA2, nameA2, skillA2] of getRobots()) { ->[numberA2, nameA2, skillA2] : (number | string)[] +>[numberA2, nameA2, skillA2] : [number, string, string] >numberA2 : number >nameA2 : string >skillA2 : string @@ -292,7 +292,7 @@ for ([numberA2, nameA2, skillA2] of getRobots()) { >nameA2 : string } for ([numberA2, nameA2, skillA2] of [robotA, robotB]) { ->[numberA2, nameA2, skillA2] : (number | string)[] +>[numberA2, nameA2, skillA2] : [number, string, string] >numberA2 : number >nameA2 : string >skillA2 : string @@ -308,9 +308,9 @@ for ([numberA2, nameA2, skillA2] of [robotA, robotB]) { >nameA2 : string } for ([nameMA, [primarySkillA, secondarySkillA]] of multiRobots) { ->[nameMA, [primarySkillA, secondarySkillA]] : (string | string[])[] +>[nameMA, [primarySkillA, secondarySkillA]] : [string, [string, string]] >nameMA : string ->[primarySkillA, secondarySkillA] : string[] +>[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string >multiRobots : [string, [string, string]][] @@ -323,9 +323,9 @@ for ([nameMA, [primarySkillA, secondarySkillA]] of multiRobots) { >nameMA : string } for ([nameMA, [primarySkillA, secondarySkillA]] of getMultiRobots()) { ->[nameMA, [primarySkillA, secondarySkillA]] : (string | string[])[] +>[nameMA, [primarySkillA, secondarySkillA]] : [string, [string, string]] >nameMA : string ->[primarySkillA, secondarySkillA] : string[] +>[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string >getMultiRobots() : [string, [string, string]][] @@ -339,9 +339,9 @@ for ([nameMA, [primarySkillA, secondarySkillA]] of getMultiRobots()) { >nameMA : string } for ([nameMA, [primarySkillA, secondarySkillA]] of [multiRobotA, multiRobotB]) { ->[nameMA, [primarySkillA, secondarySkillA]] : (string | string[])[] +>[nameMA, [primarySkillA, secondarySkillA]] : [string, [string, string]] >nameMA : string ->[primarySkillA, secondarySkillA] : string[] +>[primarySkillA, secondarySkillA] : [string, string] >primarySkillA : string >secondarySkillA : string >[multiRobotA, multiRobotB] : [string, [string, string]][] diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types index 14189ad9d81..5f580ad38f4 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForOfArrayBindingPatternDefaultValues2.types @@ -93,7 +93,7 @@ let numberA3: number, robotAInfo: (number | string)[], multiRobotAInfo: (string >multiRobotAInfo : (string | [string, string])[] for ([, nameA = "noName"] of robots) { ->[, nameA = "noName"] : string[] +>[, nameA = "noName"] : [undefined, string] > : undefined >nameA = "noName" : string >nameA : string @@ -108,7 +108,7 @@ for ([, nameA = "noName"] of robots) { >nameA : string } for ([, nameA = "noName"] of getRobots()) { ->[, nameA = "noName"] : string[] +>[, nameA = "noName"] : [undefined, string] > : undefined >nameA = "noName" : string >nameA : string @@ -124,7 +124,7 @@ for ([, nameA = "noName"] of getRobots()) { >nameA : string } for ([, nameA = "noName"] of [robotA, robotB]) { ->[, nameA = "noName"] : string[] +>[, nameA = "noName"] : [undefined, string] > : undefined >nameA = "noName" : string >nameA : string @@ -141,7 +141,7 @@ for ([, nameA = "noName"] of [robotA, robotB]) { >nameA : string } for ([, [ ->[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [string, string][] +>[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [undefined, [string, string]] > : undefined >[ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"] : [string, string] >[ primarySkillA = "primary", secondarySkillA = "secondary"] : [string, string] @@ -170,7 +170,7 @@ for ([, [ >primarySkillA : string } for ([, [ ->[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [string, string][] +>[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [undefined, [string, string]] > : undefined >[ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"] : [string, string] >[ primarySkillA = "primary", secondarySkillA = "secondary"] : [string, string] @@ -200,7 +200,7 @@ for ([, [ >primarySkillA : string } for ([, [ ->[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [string, string][] +>[, [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [undefined, [string, string]] > : undefined >[ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"] : [string, string] >[ primarySkillA = "primary", secondarySkillA = "secondary"] : [string, string] @@ -232,7 +232,7 @@ for ([, [ } for ([numberB = -1] of robots) { ->[numberB = -1] : number[] +>[numberB = -1] : [number] >numberB = -1 : number >numberB : number >-1 : number @@ -247,7 +247,7 @@ for ([numberB = -1] of robots) { >numberB : number } for ([numberB = -1] of getRobots()) { ->[numberB = -1] : number[] +>[numberB = -1] : [number] >numberB = -1 : number >numberB : number >-1 : number @@ -263,7 +263,7 @@ for ([numberB = -1] of getRobots()) { >numberB : number } for ([numberB = -1] of [robotA, robotB]) { ->[numberB = -1] : number[] +>[numberB = -1] : [number] >numberB = -1 : number >numberB : number >-1 : number @@ -280,7 +280,7 @@ for ([numberB = -1] of [robotA, robotB]) { >numberB : number } for ([nameB = "noName"] of multiRobots) { ->[nameB = "noName"] : string[] +>[nameB = "noName"] : [string] >nameB = "noName" : string >nameB : string >"noName" : string @@ -294,7 +294,7 @@ for ([nameB = "noName"] of multiRobots) { >nameB : string } for ([nameB = "noName"] of getMultiRobots()) { ->[nameB = "noName"] : string[] +>[nameB = "noName"] : [string] >nameB = "noName" : string >nameB : string >"noName" : string @@ -309,7 +309,7 @@ for ([nameB = "noName"] of getMultiRobots()) { >nameB : string } for ([nameB = "noName"] of [multiRobotA, multiRobotB]) { ->[nameB = "noName"] : string[] +>[nameB = "noName"] : [string] >nameB = "noName" : string >nameB : string >"noName" : string @@ -326,7 +326,7 @@ for ([nameB = "noName"] of [multiRobotA, multiRobotB]) { } for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of robots) { ->[numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] : (number | string)[] +>[numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] : [number, string, string] >numberA2 = -1 : number >numberA2 : number >-1 : number @@ -347,7 +347,7 @@ for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of robots) { >nameA2 : string } for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of getRobots()) { ->[numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] : (number | string)[] +>[numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] : [number, string, string] >numberA2 = -1 : number >numberA2 : number >-1 : number @@ -369,7 +369,7 @@ for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of getRobots()) { >nameA2 : string } for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of [robotA, robotB]) { ->[numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] : (number | string)[] +>[numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] : [number, string, string] >numberA2 = -1 : number >numberA2 : number >-1 : number @@ -392,7 +392,7 @@ for ([numberA2 = -1, nameA2 = "noName", skillA2 = "skill"] of [robotA, robotB]) >nameA2 : string } for ([nameMA = "noName", [ ->[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : (string | [string, string])[] +>[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [string, [string, string]] >nameMA = "noName" : string >nameMA : string >"noName" : string @@ -423,7 +423,7 @@ for ([nameMA = "noName", [ >nameMA : string } for ([nameMA = "noName", [ ->[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : (string | [string, string])[] +>[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [string, [string, string]] >nameMA = "noName" : string >nameMA : string >"noName" : string @@ -455,7 +455,7 @@ for ([nameMA = "noName", [ >nameMA : string } for ([nameMA = "noName", [ ->[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : (string | [string, string])[] +>[nameMA = "noName", [ primarySkillA = "primary", secondarySkillA = "secondary"] = ["skill1", "skill2"]] : [string, [string, string]] >nameMA = "noName" : string >nameMA : string >"noName" : string diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForOfObjectBindingPatternDefaultValues2.types b/tests/baselines/reference/sourceMapValidationDestructuringForOfObjectBindingPatternDefaultValues2.types index fe630aafccc..adb5d515fe4 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForOfObjectBindingPatternDefaultValues2.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForOfObjectBindingPatternDefaultValues2.types @@ -102,7 +102,7 @@ let name: string, primary: string, secondary: string, skill: string; >skill : string for ({name: nameA = "noName" } of robots) { ->{name: nameA = "noName" } : { name: string; } +>{name: nameA = "noName" } : { name?: string; } >name : Robot >nameA = "noName" : string >nameA : string @@ -117,7 +117,7 @@ for ({name: nameA = "noName" } of robots) { >nameA : string } for ({name: nameA = "noName" } of getRobots()) { ->{name: nameA = "noName" } : { name: string; } +>{name: nameA = "noName" } : { name?: string; } >name : Robot >nameA = "noName" : string >nameA : string @@ -133,7 +133,7 @@ for ({name: nameA = "noName" } of getRobots()) { >nameA : string } for ({name: nameA = "noName" } of [{ name: "mower", skill: "mowing" }, { name: "trimmer", skill: "trimming" }]) { ->{name: nameA = "noName" } : { name: string; } +>{name: nameA = "noName" } : { name?: string; } >name : { name: string; skill: string; } >nameA = "noName" : string >nameA : string @@ -158,7 +158,7 @@ for ({name: nameA = "noName" } of [{ name: "mower", skill: "mowing" }, { name: " >nameA : string } for ({ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = ->{ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } } : { skills: { primary?: string; secondary?: string; }; } +>{ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } } : { skills?: { primary?: string; secondary?: string; }; } >skills : MultiRobot >{ primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } : { primary?: string; secondary?: string; } >{ primary: primaryA = "primary", secondary: secondaryA = "secondary" } : { primary?: string; secondary?: string; } @@ -187,7 +187,7 @@ for ({ skills: { primary: primaryA = "primary", secondary: secondaryA = "seconda >primaryA : string } for ({ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = ->{ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } } : { skills: { primary?: string; secondary?: string; }; } +>{ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } } : { skills?: { primary?: string; secondary?: string; }; } >skills : MultiRobot >{ primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } : { primary?: string; secondary?: string; } >{ primary: primaryA = "primary", secondary: secondaryA = "secondary" } : { primary?: string; secondary?: string; } @@ -217,7 +217,7 @@ for ({ skills: { primary: primaryA = "primary", secondary: secondaryA = "seconda >primaryA : string } for ({ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = ->{ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } } : { skills: { primary?: string; secondary?: string; }; } +>{ skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } } : { skills?: { primary?: string; secondary?: string; }; } >skills : MultiRobot >{ primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "nosKill", secondary: "noSkill" } : { primary?: string; secondary?: string; } >{ primary: primaryA = "primary", secondary: secondaryA = "secondary" } : { primary?: string; secondary?: string; } @@ -271,7 +271,7 @@ for ({ skills: { primary: primaryA = "primary", secondary: secondaryA = "seconda } for ({ name = "noName" } of robots) { ->{ name = "noName" } : { name: string; } +>{ name = "noName" } : { name?: string; } >name : Robot >robots : Robot[] @@ -283,7 +283,7 @@ for ({ name = "noName" } of robots) { >nameA : string } for ({ name = "noName" } of getRobots()) { ->{ name = "noName" } : { name: string; } +>{ name = "noName" } : { name?: string; } >name : Robot >getRobots() : Robot[] >getRobots : () => Robot[] @@ -296,7 +296,7 @@ for ({ name = "noName" } of getRobots()) { >nameA : string } for ({ name = "noName" } of [{ name: "mower", skill: "mowing" }, { name: "trimmer", skill: "trimming" }]) { ->{ name = "noName" } : { name: string; } +>{ name = "noName" } : { name?: string; } >name : { name: string; skill: string; } >[{ name: "mower", skill: "mowing" }, { name: "trimmer", skill: "trimming" }] : { name: string; skill: string; }[] >{ name: "mower", skill: "mowing" } : { name: string; skill: string; } @@ -318,7 +318,7 @@ for ({ name = "noName" } of [{ name: "mower", skill: "mowing" }, { name: "trimme >nameA : string } for ({ ->{ skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { skills: { primary?: string; secondary?: string; }; } +>{ skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { skills?: { primary?: string; secondary?: string; }; } skills: { >skills : MultiRobot @@ -349,7 +349,7 @@ for ({ >primaryA : string } for ({ ->{ skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { skills: { primary?: string; secondary?: string; }; } +>{ skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { skills?: { primary?: string; secondary?: string; }; } skills: { >skills : MultiRobot @@ -381,7 +381,7 @@ for ({ >primaryA : string } for ({ ->{ skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { skills: { primary?: string; secondary?: string; }; } +>{ skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { skills?: { primary?: string; secondary?: string; }; } skills: { >skills : { name: string; skills: { primary: string; secondary: string; }; } @@ -434,7 +434,7 @@ for ({ for ({name: nameA = "noName", skill: skillA = "noSkill" } of robots) { ->{name: nameA = "noName", skill: skillA = "noSkill" } : { name: string; skill: string; } +>{name: nameA = "noName", skill: skillA = "noSkill" } : { name?: string; skill?: string; } >name : Robot >nameA = "noName" : string >nameA : string @@ -453,7 +453,7 @@ for ({name: nameA = "noName", skill: skillA = "noSkill" } of robots) { >nameA : string } for ({name: nameA = "noName", skill: skillA = "noSkill" } of getRobots()) { ->{name: nameA = "noName", skill: skillA = "noSkill" } : { name: string; skill: string; } +>{name: nameA = "noName", skill: skillA = "noSkill" } : { name?: string; skill?: string; } >name : Robot >nameA = "noName" : string >nameA : string @@ -473,7 +473,7 @@ for ({name: nameA = "noName", skill: skillA = "noSkill" } of getRobots()) { >nameA : string } for ({name: nameA = "noName", skill: skillA = "noSkill" } of [{ name: "mower", skill: "mowing" }, { name: "trimmer", skill: "trimming" }]) { ->{name: nameA = "noName", skill: skillA = "noSkill" } : { name: string; skill: string; } +>{name: nameA = "noName", skill: skillA = "noSkill" } : { name?: string; skill?: string; } >name : { name: string; skill: string; } >nameA = "noName" : string >nameA : string @@ -502,7 +502,7 @@ for ({name: nameA = "noName", skill: skillA = "noSkill" } of [{ name: "mower", >nameA : string } for ({ ->{ name: nameA = "noName", skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name: string; skills: { primary?: string; secondary?: string; }; } +>{ name: nameA = "noName", skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name?: string; skills?: { primary?: string; secondary?: string; }; } name: nameA = "noName", >name : MultiRobot @@ -545,7 +545,7 @@ for ({ >nameA : string } for ({ ->{ name: nameA = "noName", skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name: string; skills: { primary?: string; secondary?: string; }; } +>{ name: nameA = "noName", skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name?: string; skills?: { primary?: string; secondary?: string; }; } name: nameA = "noName", >name : MultiRobot @@ -589,7 +589,7 @@ for ({ >nameA : string } for ({ ->{ name: nameA = "noName", skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name: string; skills: { primary?: string; secondary?: string; }; } +>{ name: nameA = "noName", skills: { primary: primaryA = "primary", secondary: secondaryA = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name?: string; skills?: { primary?: string; secondary?: string; }; } name: nameA = "noName", >name : MultiRobot @@ -655,7 +655,7 @@ for ({ } for ({ name = "noName", skill = "noSkill" } of robots) { ->{ name = "noName", skill = "noSkill" } : { name: string; skill: string; } +>{ name = "noName", skill = "noSkill" } : { name?: string; skill?: string; } >name : Robot >skill : Robot >robots : Robot[] @@ -668,7 +668,7 @@ for ({ name = "noName", skill = "noSkill" } of robots) { >nameA : string } for ({ name = "noName", skill = "noSkill" } of getRobots()) { ->{ name = "noName", skill = "noSkill" } : { name: string; skill: string; } +>{ name = "noName", skill = "noSkill" } : { name?: string; skill?: string; } >name : Robot >skill : Robot >getRobots() : Robot[] @@ -682,7 +682,7 @@ for ({ name = "noName", skill = "noSkill" } of getRobots()) { >nameA : string } for ({ name = "noName", skill = "noSkill" } of [{ name: "mower", skill: "mowing" }, { name: "trimmer", skill: "trimming" }]) { ->{ name = "noName", skill = "noSkill" } : { name: string; skill: string; } +>{ name = "noName", skill = "noSkill" } : { name?: string; skill?: string; } >name : { name: string; skill: string; } >skill : { name: string; skill: string; } >[{ name: "mower", skill: "mowing" }, { name: "trimmer", skill: "trimming" }] : { name: string; skill: string; }[] @@ -705,7 +705,7 @@ for ({ name = "noName", skill = "noSkill" } of [{ name: "mower", skill: "mowing >nameA : string } for ({ ->{ name = "noName", skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name: string; skills: { primary?: string; secondary?: string; }; } +>{ name = "noName", skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name?: string; skills?: { primary?: string; secondary?: string; }; } name = "noName", >name : MultiRobot @@ -739,7 +739,7 @@ for ({ >nameA : string } for ({ ->{ name = "noName", skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name: string; skills: { primary?: string; secondary?: string; }; } +>{ name = "noName", skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name?: string; skills?: { primary?: string; secondary?: string; }; } name = "noName", >name : MultiRobot @@ -774,7 +774,7 @@ for ({ >nameA : string } for ({ ->{ name = "noName", skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name: string; skills: { primary?: string; secondary?: string; }; } +>{ name = "noName", skills: { primary = "primary", secondary = "secondary" } = { primary: "noSkill", secondary: "noSkill" }} : { name?: string; skills?: { primary?: string; secondary?: string; }; } name = "noName", >name : { name: string; skills: { primary: string; secondary: string; }; } diff --git a/tests/baselines/reference/systemModule13.types b/tests/baselines/reference/systemModule13.types index 35f22be98b8..f31b0825416 100644 --- a/tests/baselines/reference/systemModule13.types +++ b/tests/baselines/reference/systemModule13.types @@ -24,7 +24,7 @@ export const {a: z0, b: {c: z1}} = {a: true, b: {c: "123"}}; >"123" : string for ([x] of [[1]]) {} ->[x] : number[] +>[x] : [number] >x : number >[[1]] : number[][] >[1] : number[] diff --git a/tests/baselines/reference/systemModule8.types b/tests/baselines/reference/systemModule8.types index 2c3dd1e48bb..940067c5653 100644 --- a/tests/baselines/reference/systemModule8.types +++ b/tests/baselines/reference/systemModule8.types @@ -135,7 +135,7 @@ export const {a: z0, b: {c: z1}} = {a: true, b: {c: "123"}}; >"123" : string for ([x] of [[1]]) {} ->[x] : any[] +>[x] : [any] >x : any >[[1]] : number[][] >[1] : number[] From 0820249e710e3c148eea558388afc7d5e6559f98 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 26 Mar 2016 08:20:06 -0700 Subject: [PATCH 017/110] Fixing some tests --- .../typeGuardsInConditionalExpression.ts | 48 ++++++++----------- .../typeGuards/typeGuardsInIfStatement.ts | 35 ++++++-------- ...ypeGuardsInRightOperandOfAndAndOperator.ts | 19 ++------ .../typeGuardsInRightOperandOfOrOrOperator.ts | 16 ++----- .../unionTypesAssignability.ts | 19 ++++---- 5 files changed, 51 insertions(+), 86 deletions(-) diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts index 1633c80ab67..01f9361ebc3 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts @@ -11,43 +11,37 @@ function foo(x: number | string) { : x++; // number } function foo2(x: number | string) { - // x is assigned in the if true branch, the type is not narrowed return typeof x === "string" - ? (x = 10 && x)// string | number - : x; // string | number + ? ((x = "hello") && x) // string + : x; // number } function foo3(x: number | string) { - // x is assigned in the if false branch, the type is not narrowed - // even though assigned using same type as narrowed expression return typeof x === "string" - ? (x = "Hello" && x) // string | number - : x; // string | number + ? ((x = 10) && x) // number + : x; // number } function foo4(x: number | string) { - // false branch updates the variable - so here it is not number - // even though assigned using same type as narrowed expression return typeof x === "string" - ? x // string | number - : (x = 10 && x); // string | number + ? x // string + : ((x = 10) && x); // number } function foo5(x: number | string) { - // false branch updates the variable - so here it is not number return typeof x === "string" - ? x // string | number - : (x = "hello" && x); // string | number + ? x // string + : ((x = "hello") && x); // string } function foo6(x: number | string) { // Modify in both branches return typeof x === "string" - ? (x = 10 && x) // string | number - : (x = "hello" && x); // string | number + ? ((x = 10) && x) // number + : ((x = "hello") && x); // string } function foo7(x: number | string | boolean) { return typeof x === "string" - ? x === "hello" // string + ? x === "hello" // boolean : typeof x === "boolean" ? x // boolean - : x == 10; // number + : x == 10; // boolean } function foo8(x: number | string | boolean) { var b: number | boolean; @@ -56,14 +50,14 @@ function foo8(x: number | string | boolean) { : ((b = x) && // number | boolean (typeof x === "boolean" ? x // boolean - : x == 10)); // number + : x == 10)); // boolean } function foo9(x: number | string) { var y = 10; // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop return typeof x === "string" - ? ((y = x.length) && x === "hello") // string - : x === 10; // number + ? ((y = x.length) && x === "hello") // boolean + : x === 10; // boolean } function foo10(x: number | string | boolean) { // Mixing typeguards @@ -76,22 +70,20 @@ function foo10(x: number | string | boolean) { } function foo11(x: number | string | boolean) { // Mixing typeguards - // Assigning value to x deep inside another guard stops narrowing of type too var b: number | boolean | string; return typeof x === "string" - ? x // number | boolean | string - changed in the false branch - : ((b = x) // x is number | boolean | string - because the assignment changed it + ? x // string + : ((b = x) // x is number | boolean && typeof x === "number" && (x = 10) // assignment to x - && x); // x is number | boolean | string + && x); // x is number } function foo12(x: number | string | boolean) { // Mixing typeguards - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression var b: number | boolean | string; return typeof x === "string" - ? (x = 10 && x.toString().length) // number | boolean | string - changed here - : ((b = x) // x is number | boolean | string - changed in true branch + ? ((x = 10) && x.toString().length) // number + : ((b = x) // x is number | boolean && typeof x === "number" && x); // x is number } \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts index f72845c18a4..1626cfdb82e 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts @@ -1,9 +1,7 @@ // In the true branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true, -// provided the true branch statement contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true. // In the false branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false, -// provided the false branch statement contains no assignments to the variable or parameter +// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false. function foo(x: number | string) { if (typeof x === "string") { return x.length; // string @@ -13,54 +11,49 @@ function foo(x: number | string) { } } function foo2(x: number | string) { - // x is assigned in the if true branch, the type is not narrowed if (typeof x === "string") { x = 10; - return x; // string | number + return x; // number } else { - return x; // string | number + return x; // number } } function foo3(x: number | string) { - // x is assigned in the if true branch, the type is not narrowed if (typeof x === "string") { - x = "Hello"; // even though assigned using same type as narrowed expression - return x; // string | number + x = "Hello"; + return x; // string } else { - return x; // string | number + return x; // number } } function foo4(x: number | string) { - // false branch updates the variable - so here it is not number if (typeof x === "string") { - return x; // string | number + return x; // string } else { - x = 10; // even though assigned number - this should result in x to be string | number - return x; // string | number + x = 10; + return x; // number } } function foo5(x: number | string) { - // false branch updates the variable - so here it is not number if (typeof x === "string") { - return x; // string | number + return x; // string } else { x = "hello"; - return x; // string | number + return x; // string } } function foo6(x: number | string) { - // Modify in both branches if (typeof x === "string") { x = 10; - return x; // string | number + return x; // number } else { x = "hello"; - return x; // string | number + return x; // string } } function foo7(x: number | string | boolean) { diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts index da0d8ce24b5..acd71f37d91 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts @@ -1,6 +1,5 @@ // In the right operand of a && operation, -// the type of a variable or parameter is narrowed by any type guard in the left operand when true, -// provided the right operand contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the left operand when true. function foo(x: number | string) { return typeof x === "string" && x.length === 10; // string } @@ -35,21 +34,11 @@ function foo7(x: number | string | boolean) { var y: number| boolean | string; var z: number| boolean | string; // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x !== "string" - && ((z = x) // string | number | boolean - x changed deeper in conditional expression + && ((z = x) // number | boolean && (typeof x === "number" // change value of x - ? (x = 10 && x.toString()) // number | boolean | string + ? ((x = 10) && x.toString()) // x is number // do not change value - : (y = x && x.toString()))); // number | boolean | string + : ((y = x) && x.toString()))); // x is boolean } -function foo8(x: number | string) { - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x !== "string" - && (x = 10) // change x - number| string - && (typeof x === "number" - ? x // number - : x.length); // string -} \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts index 867dc143a85..131e5dd10bc 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts @@ -35,21 +35,11 @@ function foo7(x: number | string | boolean) { var y: number| boolean | string; var z: number| boolean | string; // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x === "string" - || ((z = x) // string | number | boolean - x changed deeper in conditional expression + || ((z = x) // number | boolean || (typeof x === "number" // change value of x - ? (x = 10 && x.toString()) // number | boolean | string + ? ((x = 10) && x.toString()) // number | boolean | string // do not change value - : (y = x && x.toString()))); // number | boolean | string + : ((y = x) && x.toString()))); // number | boolean | string } -function foo8(x: number | string) { - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x === "string" - || (x = 10) // change x - number| string - || (typeof x === "number" - ? x // number - : x.length); // string -} \ No newline at end of file diff --git a/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts b/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts index 9ceee8845a5..90f16b6d15d 100644 --- a/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts +++ b/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts @@ -59,13 +59,14 @@ unionNumberString = null; unionDE = undefined; unionNumberString = undefined; -// type parameters -function foo(t: T, u: U) { - t = u; // error - u = t; // error - var x : T | U; - x = t; // ok - x = u; // ok - t = x; // error U not assignable to T - u = x; // error T not assignable to U +// type parameters +function foo(t: T, u: U) { + t = u; // error + u = t; // error + var x : T | U; + x = t; // ok + x = u; // ok + x = undefined; + t = x; // error U not assignable to T + u = x; // error T not assignable to U } From 5a5d89a71e3842366086bf2fda3b45394f34cc05 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 26 Mar 2016 08:21:43 -0700 Subject: [PATCH 018/110] Accepting new baselines --- .../reference/typeAssertions.errors.txt | 11 +- .../typeGuardsInConditionalExpression.js | 96 ++--- .../typeGuardsInConditionalExpression.symbols | 238 +++++----- .../typeGuardsInConditionalExpression.types | 185 ++++---- .../reference/typeGuardsInDoStatement.js | 60 +++ .../reference/typeGuardsInDoStatement.symbols | 74 ++++ .../reference/typeGuardsInDoStatement.types | 92 ++++ .../reference/typeGuardsInForStatement.js | 48 +++ .../typeGuardsInForStatement.symbols | 62 +++ .../reference/typeGuardsInForStatement.types | 77 ++++ .../typeGuardsInIfStatement.errors.txt | 153 +++++++ .../reference/typeGuardsInIfStatement.js | 70 ++- .../reference/typeGuardsInIfStatement.symbols | 304 ------------- .../reference/typeGuardsInIfStatement.types | 405 ------------------ ...ypeGuardsInRightOperandOfAndAndOperator.js | 39 +- ...ardsInRightOperandOfAndAndOperator.symbols | 130 +++--- ...GuardsInRightOperandOfAndAndOperator.types | 107 ++--- .../typeGuardsInRightOperandOfOrOrOperator.js | 33 +- ...GuardsInRightOperandOfOrOrOperator.symbols | 37 +- ...peGuardsInRightOperandOfOrOrOperator.types | 104 ++--- .../reference/typeGuardsInWhileStatement.js | 54 +++ .../typeGuardsInWhileStatement.symbols | 62 +++ .../typeGuardsInWhileStatement.types | 74 ++++ .../unionTypesAssignability.errors.txt | 5 +- .../reference/unionTypesAssignability.js | 2 + 25 files changed, 1193 insertions(+), 1329 deletions(-) create mode 100644 tests/baselines/reference/typeGuardsInDoStatement.js create mode 100644 tests/baselines/reference/typeGuardsInDoStatement.symbols create mode 100644 tests/baselines/reference/typeGuardsInDoStatement.types create mode 100644 tests/baselines/reference/typeGuardsInForStatement.js create mode 100644 tests/baselines/reference/typeGuardsInForStatement.symbols create mode 100644 tests/baselines/reference/typeGuardsInForStatement.types create mode 100644 tests/baselines/reference/typeGuardsInIfStatement.errors.txt delete mode 100644 tests/baselines/reference/typeGuardsInIfStatement.symbols delete mode 100644 tests/baselines/reference/typeGuardsInIfStatement.types create mode 100644 tests/baselines/reference/typeGuardsInWhileStatement.js create mode 100644 tests/baselines/reference/typeGuardsInWhileStatement.symbols create mode 100644 tests/baselines/reference/typeGuardsInWhileStatement.types diff --git a/tests/baselines/reference/typeAssertions.errors.txt b/tests/baselines/reference/typeAssertions.errors.txt index c7401e4fcf9..9a9644d8b8f 100644 --- a/tests/baselines/reference/typeAssertions.errors.txt +++ b/tests/baselines/reference/typeAssertions.errors.txt @@ -1,10 +1,13 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(5,5): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. Property 'p' is missing in type 'SomeOther'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. Property 'x' is missing in type 'SomeOther'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(37,13): error TS2352: Neither type 'SomeDerived' nor type 'SomeOther' is assignable to the other. Property 'q' is missing in type 'SomeDerived'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. Property 'q' is missing in type 'SomeBase'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,5): error TS2304: Cannot find name 'numOrStr'. @@ -23,7 +26,7 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,44): err tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): error TS1005: ';' expected. -==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (18 errors) ==== +==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (21 errors) ==== // Function call whose argument is a 1 arg generic function call with explicit type arguments function fn1(t: T) { } function fn2(t: any) { } @@ -58,6 +61,8 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err someBase = someBase; someBase = someOther; // Error ~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. + ~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. !!! error TS2352: Property 'p' is missing in type 'SomeOther'. @@ -65,6 +70,8 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err someDerived = someBase; someDerived = someOther; // Error ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. + ~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. !!! error TS2352: Property 'x' is missing in type 'SomeOther'. @@ -74,6 +81,8 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err !!! error TS2352: Property 'q' is missing in type 'SomeDerived'. someOther = someBase; // Error ~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. + ~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. !!! error TS2352: Property 'q' is missing in type 'SomeBase'. someOther = someOther; diff --git a/tests/baselines/reference/typeGuardsInConditionalExpression.js b/tests/baselines/reference/typeGuardsInConditionalExpression.js index 118ebbc02c0..9aade91612a 100644 --- a/tests/baselines/reference/typeGuardsInConditionalExpression.js +++ b/tests/baselines/reference/typeGuardsInConditionalExpression.js @@ -12,43 +12,37 @@ function foo(x: number | string) { : x++; // number } function foo2(x: number | string) { - // x is assigned in the if true branch, the type is not narrowed return typeof x === "string" - ? (x = 10 && x)// string | number - : x; // string | number + ? ((x = "hello") && x) // string + : x; // number } function foo3(x: number | string) { - // x is assigned in the if false branch, the type is not narrowed - // even though assigned using same type as narrowed expression return typeof x === "string" - ? (x = "Hello" && x) // string | number - : x; // string | number + ? ((x = 10) && x) // number + : x; // number } function foo4(x: number | string) { - // false branch updates the variable - so here it is not number - // even though assigned using same type as narrowed expression return typeof x === "string" - ? x // string | number - : (x = 10 && x); // string | number + ? x // string + : ((x = 10) && x); // number } function foo5(x: number | string) { - // false branch updates the variable - so here it is not number return typeof x === "string" - ? x // string | number - : (x = "hello" && x); // string | number + ? x // string + : ((x = "hello") && x); // string } function foo6(x: number | string) { // Modify in both branches return typeof x === "string" - ? (x = 10 && x) // string | number - : (x = "hello" && x); // string | number + ? ((x = 10) && x) // number + : ((x = "hello") && x); // string } function foo7(x: number | string | boolean) { return typeof x === "string" - ? x === "hello" // string + ? x === "hello" // boolean : typeof x === "boolean" ? x // boolean - : x == 10; // number + : x == 10; // boolean } function foo8(x: number | string | boolean) { var b: number | boolean; @@ -57,14 +51,14 @@ function foo8(x: number | string | boolean) { : ((b = x) && // number | boolean (typeof x === "boolean" ? x // boolean - : x == 10)); // number + : x == 10)); // boolean } function foo9(x: number | string) { var y = 10; // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop return typeof x === "string" - ? ((y = x.length) && x === "hello") // string - : x === 10; // number + ? ((y = x.length) && x === "hello") // boolean + : x === 10; // boolean } function foo10(x: number | string | boolean) { // Mixing typeguards @@ -77,22 +71,20 @@ function foo10(x: number | string | boolean) { } function foo11(x: number | string | boolean) { // Mixing typeguards - // Assigning value to x deep inside another guard stops narrowing of type too var b: number | boolean | string; return typeof x === "string" - ? x // number | boolean | string - changed in the false branch - : ((b = x) // x is number | boolean | string - because the assignment changed it + ? x // string + : ((b = x) // x is number | boolean && typeof x === "number" && (x = 10) // assignment to x - && x); // x is number | boolean | string + && x); // x is number } function foo12(x: number | string | boolean) { // Mixing typeguards - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression var b: number | boolean | string; return typeof x === "string" - ? (x = 10 && x.toString().length) // number | boolean | string - changed here - : ((b = x) // x is number | boolean | string - changed in true branch + ? ((x = 10) && x.toString().length) // number + : ((b = x) // x is number | boolean && typeof x === "number" && x); // x is number } @@ -110,43 +102,37 @@ function foo(x) { : x++; // number } function foo2(x) { - // x is assigned in the if true branch, the type is not narrowed return typeof x === "string" - ? (x = 10 && x) // string | number - : x; // string | number + ? ((x = "hello") && x) // string + : x; // number } function foo3(x) { - // x is assigned in the if false branch, the type is not narrowed - // even though assigned using same type as narrowed expression return typeof x === "string" - ? (x = "Hello" && x) // string | number - : x; // string | number + ? ((x = 10) && x) // number + : x; // number } function foo4(x) { - // false branch updates the variable - so here it is not number - // even though assigned using same type as narrowed expression return typeof x === "string" - ? x // string | number - : (x = 10 && x); // string | number + ? x // string + : ((x = 10) && x); // number } function foo5(x) { - // false branch updates the variable - so here it is not number return typeof x === "string" - ? x // string | number - : (x = "hello" && x); // string | number + ? x // string + : ((x = "hello") && x); // string } function foo6(x) { // Modify in both branches return typeof x === "string" - ? (x = 10 && x) // string | number - : (x = "hello" && x); // string | number + ? ((x = 10) && x) // number + : ((x = "hello") && x); // string } function foo7(x) { return typeof x === "string" - ? x === "hello" // string + ? x === "hello" // boolean : typeof x === "boolean" ? x // boolean - : x == 10; // number + : x == 10; // boolean } function foo8(x) { var b; @@ -155,14 +141,14 @@ function foo8(x) { : ((b = x) && (typeof x === "boolean" ? x // boolean - : x == 10)); // number + : x == 10)); // boolean } function foo9(x) { var y = 10; // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop return typeof x === "string" - ? ((y = x.length) && x === "hello") // string - : x === 10; // number + ? ((y = x.length) && x === "hello") // boolean + : x === 10; // boolean } function foo10(x) { // Mixing typeguards @@ -175,22 +161,20 @@ function foo10(x) { } function foo11(x) { // Mixing typeguards - // Assigning value to x deep inside another guard stops narrowing of type too var b; return typeof x === "string" - ? x // number | boolean | string - changed in the false branch - : ((b = x) // x is number | boolean | string - because the assignment changed it + ? x // string + : ((b = x) // x is number | boolean && typeof x === "number" && (x = 10) // assignment to x - && x); // x is number | boolean | string + && x); // x is number } function foo12(x) { // Mixing typeguards - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression var b; return typeof x === "string" - ? (x = 10 && x.toString().length) // number | boolean | string - changed here - : ((b = x) // x is number | boolean | string - changed in true branch + ? ((x = 10) && x.toString().length) // number + : ((b = x) // x is number | boolean && typeof x === "number" && x); // x is number } diff --git a/tests/baselines/reference/typeGuardsInConditionalExpression.symbols b/tests/baselines/reference/typeGuardsInConditionalExpression.symbols index 7de63d90bf9..ada6a6d99fd 100644 --- a/tests/baselines/reference/typeGuardsInConditionalExpression.symbols +++ b/tests/baselines/reference/typeGuardsInConditionalExpression.symbols @@ -25,227 +25,219 @@ function foo2(x: number | string) { >foo2 : Symbol(foo2, Decl(typeGuardsInConditionalExpression.ts, 11, 1)) >x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14)) - // x is assigned in the if true branch, the type is not narrowed return typeof x === "string" >x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14)) - ? (x = 10 && x)// string | number + ? ((x = "hello") && x) // string >x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14)) >x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14)) - : x; // string | number + : x; // number >x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14)) } function foo3(x: number | string) { ->foo3 : Symbol(foo3, Decl(typeGuardsInConditionalExpression.ts, 17, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14)) +>foo3 : Symbol(foo3, Decl(typeGuardsInConditionalExpression.ts, 16, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 17, 14)) - // x is assigned in the if false branch, the type is not narrowed - // even though assigned using same type as narrowed expression return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 17, 14)) - ? (x = "Hello" && x) // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14)) + ? ((x = 10) && x) // number +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 17, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 17, 14)) - : x; // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14)) + : x; // number +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 17, 14)) } function foo4(x: number | string) { ->foo4 : Symbol(foo4, Decl(typeGuardsInConditionalExpression.ts, 24, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14)) +>foo4 : Symbol(foo4, Decl(typeGuardsInConditionalExpression.ts, 21, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 22, 14)) - // false branch updates the variable - so here it is not number - // even though assigned using same type as narrowed expression return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 22, 14)) - ? x // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14)) + ? x // string +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 22, 14)) - : (x = 10 && x); // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14)) + : ((x = 10) && x); // number +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 22, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 22, 14)) } function foo5(x: number | string) { ->foo5 : Symbol(foo5, Decl(typeGuardsInConditionalExpression.ts, 31, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) +>foo5 : Symbol(foo5, Decl(typeGuardsInConditionalExpression.ts, 26, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 27, 14)) - // false branch updates the variable - so here it is not number return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 27, 14)) - ? x // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) + ? x // string +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 27, 14)) - : (x = "hello" && x); // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) + : ((x = "hello") && x); // string +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 27, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 27, 14)) } function foo6(x: number | string) { ->foo6 : Symbol(foo6, Decl(typeGuardsInConditionalExpression.ts, 37, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) +>foo6 : Symbol(foo6, Decl(typeGuardsInConditionalExpression.ts, 31, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) // Modify in both branches return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) - ? (x = 10 && x) // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) + ? ((x = 10) && x) // number +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) - : (x = "hello" && x); // string | number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) + : ((x = "hello") && x); // string +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14)) } function foo7(x: number | string | boolean) { ->foo7 : Symbol(foo7, Decl(typeGuardsInConditionalExpression.ts, 43, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14)) +>foo7 : Symbol(foo7, Decl(typeGuardsInConditionalExpression.ts, 37, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) - ? x === "hello" // string ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14)) + ? x === "hello" // boolean +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) : typeof x === "boolean" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) ? x // boolean ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) - : x == 10; // number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14)) + : x == 10; // boolean +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14)) } function foo8(x: number | string | boolean) { ->foo8 : Symbol(foo8, Decl(typeGuardsInConditionalExpression.ts, 50, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14)) +>foo8 : Symbol(foo8, Decl(typeGuardsInConditionalExpression.ts, 44, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 45, 14)) var b: number | boolean; ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 52, 7)) +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 46, 7)) return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 45, 14)) ? x === "hello" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 45, 14)) : ((b = x) && // number | boolean ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 52, 7)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14)) +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 46, 7)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 45, 14)) (typeof x === "boolean" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 45, 14)) ? x // boolean ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 45, 14)) - : x == 10)); // number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14)) + : x == 10)); // boolean +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 45, 14)) } function foo9(x: number | string) { ->foo9 : Symbol(foo9, Decl(typeGuardsInConditionalExpression.ts, 59, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14)) +>foo9 : Symbol(foo9, Decl(typeGuardsInConditionalExpression.ts, 53, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 54, 14)) var y = 10; ->y : Symbol(y, Decl(typeGuardsInConditionalExpression.ts, 61, 7)) +>y : Symbol(y, Decl(typeGuardsInConditionalExpression.ts, 55, 7)) // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 54, 14)) - ? ((y = x.length) && x === "hello") // string ->y : Symbol(y, Decl(typeGuardsInConditionalExpression.ts, 61, 7)) + ? ((y = x.length) && x === "hello") // boolean +>y : Symbol(y, Decl(typeGuardsInConditionalExpression.ts, 55, 7)) >x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 54, 14)) >length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 54, 14)) - : x === 10; // number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14)) + : x === 10; // boolean +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 54, 14)) } function foo10(x: number | string | boolean) { ->foo10 : Symbol(foo10, Decl(typeGuardsInConditionalExpression.ts, 66, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15)) +>foo10 : Symbol(foo10, Decl(typeGuardsInConditionalExpression.ts, 60, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 61, 15)) // Mixing typeguards var b: boolean | number; ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 69, 7)) +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 63, 7)) return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 61, 15)) ? x // string ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 61, 15)) : ((b = x) // x is number | boolean ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 69, 7)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15)) +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 63, 7)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 61, 15)) && typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 61, 15)) && x.toString()); // x is number >x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 61, 15)) >toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) } function foo11(x: number | string | boolean) { ->foo11 : Symbol(foo11, Decl(typeGuardsInConditionalExpression.ts, 75, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15)) +>foo11 : Symbol(foo11, Decl(typeGuardsInConditionalExpression.ts, 69, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 70, 15)) // Mixing typeguards - // Assigning value to x deep inside another guard stops narrowing of type too var b: number | boolean | string; ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 79, 7)) +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 72, 7)) return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 70, 15)) - ? x // number | boolean | string - changed in the false branch ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15)) + ? x // string +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 70, 15)) - : ((b = x) // x is number | boolean | string - because the assignment changed it ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 79, 7)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15)) + : ((b = x) // x is number | boolean +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 72, 7)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 70, 15)) && typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 70, 15)) && (x = 10) // assignment to x ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15)) - - && x); // x is number | boolean | string ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15)) -} -function foo12(x: number | string | boolean) { ->foo12 : Symbol(foo12, Decl(typeGuardsInConditionalExpression.ts, 86, 1)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15)) - - // Mixing typeguards - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - var b: number | boolean | string; ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 90, 7)) - - return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15)) - - ? (x = 10 && x.toString().length) // number | boolean | string - changed here ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15)) ->x.toString().length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->length : Symbol(String.length, Decl(lib.d.ts, --, --)) - - : ((b = x) // x is number | boolean | string - changed in true branch ->b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 90, 7)) ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15)) - - && typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 70, 15)) && x); // x is number ->x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 70, 15)) +} +function foo12(x: number | string | boolean) { +>foo12 : Symbol(foo12, Decl(typeGuardsInConditionalExpression.ts, 79, 1)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 80, 15)) + + // Mixing typeguards + var b: number | boolean | string; +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 82, 7)) + + return typeof x === "string" +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 80, 15)) + + ? ((x = 10) && x.toString().length) // number +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 80, 15)) +>x.toString().length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 80, 15)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + + : ((b = x) // x is number | boolean +>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 82, 7)) +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 80, 15)) + + && typeof x === "number" +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 80, 15)) + + && x); // x is number +>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 80, 15)) } diff --git a/tests/baselines/reference/typeGuardsInConditionalExpression.types b/tests/baselines/reference/typeGuardsInConditionalExpression.types index 493a8c0a31a..cc1459738e4 100644 --- a/tests/baselines/reference/typeGuardsInConditionalExpression.types +++ b/tests/baselines/reference/typeGuardsInConditionalExpression.types @@ -27,98 +27,96 @@ function foo(x: number | string) { >x : number } function foo2(x: number | string) { ->foo2 : (x: number | string) => number | string +>foo2 : (x: number | string) => string | number >x : number | string - // x is assigned in the if true branch, the type is not narrowed return typeof x === "string" ->typeof x === "string" ? (x = 10 && x)// string | number : x : number | string +>typeof x === "string" ? ((x = "hello") && x) // string : x : string | number >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string - ? (x = 10 && x)// string | number ->(x = 10 && x) : number | string ->x = 10 && x : number | string ->x : number | string ->10 && x : number | string ->10 : number + ? ((x = "hello") && x) // string +>((x = "hello") && x) : string +>(x = "hello") && x : string +>(x = "hello") : string +>x = "hello" : string >x : number | string +>"hello" : string +>x : string - : x; // string | number ->x : number | string + : x; // number +>x : number } function foo3(x: number | string) { ->foo3 : (x: number | string) => number | string +>foo3 : (x: number | string) => number >x : number | string - // x is assigned in the if false branch, the type is not narrowed - // even though assigned using same type as narrowed expression return typeof x === "string" ->typeof x === "string" ? (x = "Hello" && x) // string | number : x : number | string +>typeof x === "string" ? ((x = 10) && x) // number : x : number >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string - ? (x = "Hello" && x) // string | number ->(x = "Hello" && x) : number | string ->x = "Hello" && x : number | string ->x : number | string ->"Hello" && x : number | string ->"Hello" : string + ? ((x = 10) && x) // number +>((x = 10) && x) : number +>(x = 10) && x : number +>(x = 10) : number +>x = 10 : number >x : number | string +>10 : number +>x : number - : x; // string | number ->x : number | string + : x; // number +>x : number } function foo4(x: number | string) { ->foo4 : (x: number | string) => number | string +>foo4 : (x: number | string) => string | number >x : number | string - // false branch updates the variable - so here it is not number - // even though assigned using same type as narrowed expression return typeof x === "string" ->typeof x === "string" ? x // string | number : (x = 10 && x) : number | string +>typeof x === "string" ? x // string : ((x = 10) && x) : string | number >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string - ? x // string | number ->x : number | string + ? x // string +>x : string - : (x = 10 && x); // string | number ->(x = 10 && x) : number | string ->x = 10 && x : number | string + : ((x = 10) && x); // number +>((x = 10) && x) : number +>(x = 10) && x : number +>(x = 10) : number +>x = 10 : number >x : number | string ->10 && x : number | string >10 : number ->x : number | string +>x : number } function foo5(x: number | string) { ->foo5 : (x: number | string) => number | string +>foo5 : (x: number | string) => string >x : number | string - // false branch updates the variable - so here it is not number return typeof x === "string" ->typeof x === "string" ? x // string | number : (x = "hello" && x) : number | string +>typeof x === "string" ? x // string : ((x = "hello") && x) : string >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string - ? x // string | number ->x : number | string + ? x // string +>x : string - : (x = "hello" && x); // string | number ->(x = "hello" && x) : number | string ->x = "hello" && x : number | string + : ((x = "hello") && x); // string +>((x = "hello") && x) : string +>(x = "hello") && x : string +>(x = "hello") : string +>x = "hello" : string >x : number | string ->"hello" && x : number | string >"hello" : string ->x : number | string +>x : string } function foo6(x: number | string) { >foo6 : (x: number | string) => number | string @@ -126,40 +124,42 @@ function foo6(x: number | string) { // Modify in both branches return typeof x === "string" ->typeof x === "string" ? (x = 10 && x) // string | number : (x = "hello" && x) : number | string +>typeof x === "string" ? ((x = 10) && x) // number : ((x = "hello") && x) : number | string >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string - ? (x = 10 && x) // string | number ->(x = 10 && x) : number | string ->x = 10 && x : number | string + ? ((x = 10) && x) // number +>((x = 10) && x) : number +>(x = 10) && x : number +>(x = 10) : number +>x = 10 : number >x : number | string ->10 && x : number | string >10 : number ->x : number | string +>x : number - : (x = "hello" && x); // string | number ->(x = "hello" && x) : number | string ->x = "hello" && x : number | string + : ((x = "hello") && x); // string +>((x = "hello") && x) : string +>(x = "hello") && x : string +>(x = "hello") : string +>x = "hello" : string >x : number | string ->"hello" && x : number | string >"hello" : string ->x : number | string +>x : string } function foo7(x: number | string | boolean) { >foo7 : (x: number | string | boolean) => boolean >x : number | string | boolean return typeof x === "string" ->typeof x === "string" ? x === "hello" // string : typeof x === "boolean" ? x // boolean : x == 10 : boolean +>typeof x === "string" ? x === "hello" // boolean : typeof x === "boolean" ? x // boolean : x == 10 : boolean >typeof x === "string" : boolean >typeof x : string >x : number | string | boolean >"string" : string - ? x === "hello" // string + ? x === "hello" // boolean >x === "hello" : boolean >x : string >"hello" : string @@ -174,7 +174,7 @@ function foo7(x: number | string | boolean) { ? x // boolean >x : boolean - : x == 10; // number + : x == 10; // boolean >x == 10 : boolean >x : number >10 : number @@ -217,7 +217,7 @@ function foo8(x: number | string | boolean) { ? x // boolean >x : boolean - : x == 10)); // number + : x == 10)); // boolean >x == 10 : boolean >x : number >10 : number @@ -232,13 +232,13 @@ function foo9(x: number | string) { // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop return typeof x === "string" ->typeof x === "string" ? ((y = x.length) && x === "hello") // string : x === 10 : boolean +>typeof x === "string" ? ((y = x.length) && x === "hello") // boolean : x === 10 : boolean >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string - ? ((y = x.length) && x === "hello") // string + ? ((y = x.length) && x === "hello") // boolean >((y = x.length) && x === "hello") : boolean >(y = x.length) && x === "hello" : boolean >(y = x.length) : number @@ -251,7 +251,7 @@ function foo9(x: number | string) { >x : string >"hello" : string - : x === 10; // number + : x === 10; // boolean >x === 10 : boolean >x : number >10 : number @@ -296,38 +296,37 @@ function foo10(x: number | string | boolean) { >toString : (radix?: number) => string } function foo11(x: number | string | boolean) { ->foo11 : (x: number | string | boolean) => number | string | boolean +>foo11 : (x: number | string | boolean) => string | number >x : number | string | boolean // Mixing typeguards - // Assigning value to x deep inside another guard stops narrowing of type too var b: number | boolean | string; >b : number | boolean | string return typeof x === "string" ->typeof x === "string" ? x // number | boolean | string - changed in the false branch : ((b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) // assignment to x && x) : number | string | boolean +>typeof x === "string" ? x // string : ((b = x) // x is number | boolean && typeof x === "number" && (x = 10) // assignment to x && x) : string | number >typeof x === "string" : boolean >typeof x : string >x : number | string | boolean >"string" : string - ? x // number | boolean | string - changed in the false branch ->x : number | string | boolean + ? x // string +>x : string - : ((b = x) // x is number | boolean | string - because the assignment changed it ->((b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) // assignment to x && x) : number | string | boolean ->(b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) // assignment to x && x : number | string | boolean ->(b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) : number ->(b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" : boolean ->(b = x) : number | string | boolean ->b = x : number | string | boolean + : ((b = x) // x is number | boolean +>((b = x) // x is number | boolean && typeof x === "number" && (x = 10) // assignment to x && x) : number +>(b = x) // x is number | boolean && typeof x === "number" && (x = 10) // assignment to x && x : number +>(b = x) // x is number | boolean && typeof x === "number" && (x = 10) : number +>(b = x) // x is number | boolean && typeof x === "number" : boolean +>(b = x) : number | boolean +>b = x : number | boolean >b : number | boolean | string ->x : number | string | boolean +>x : number | boolean && typeof x === "number" >typeof x === "number" : boolean >typeof x : string ->x : number | string | boolean +>x : number | boolean >"number" : string && (x = 10) // assignment to x @@ -336,51 +335,51 @@ function foo11(x: number | string | boolean) { >x : number | string | boolean >10 : number - && x); // x is number | boolean | string ->x : number | string | boolean + && x); // x is number +>x : number } function foo12(x: number | string | boolean) { >foo12 : (x: number | string | boolean) => number >x : number | string | boolean // Mixing typeguards - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression var b: number | boolean | string; >b : number | boolean | string return typeof x === "string" ->typeof x === "string" ? (x = 10 && x.toString().length) // number | boolean | string - changed here : ((b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" && x) : number +>typeof x === "string" ? ((x = 10) && x.toString().length) // number : ((b = x) // x is number | boolean && typeof x === "number" && x) : number >typeof x === "string" : boolean >typeof x : string >x : number | string | boolean >"string" : string - ? (x = 10 && x.toString().length) // number | boolean | string - changed here ->(x = 10 && x.toString().length) : number ->x = 10 && x.toString().length : number + ? ((x = 10) && x.toString().length) // number +>((x = 10) && x.toString().length) : number +>(x = 10) && x.toString().length : number +>(x = 10) : number +>x = 10 : number >x : number | string | boolean ->10 && x.toString().length : number >10 : number >x.toString().length : number >x.toString() : string >x.toString : (radix?: number) => string ->x : number | string | boolean +>x : number >toString : (radix?: number) => string >length : number - : ((b = x) // x is number | boolean | string - changed in true branch ->((b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" && x) : number ->(b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" && x : number ->(b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" : boolean ->(b = x) : number | string | boolean ->b = x : number | string | boolean + : ((b = x) // x is number | boolean +>((b = x) // x is number | boolean && typeof x === "number" && x) : number +>(b = x) // x is number | boolean && typeof x === "number" && x : number +>(b = x) // x is number | boolean && typeof x === "number" : boolean +>(b = x) : number | boolean +>b = x : number | boolean >b : number | boolean | string ->x : number | string | boolean +>x : number | boolean && typeof x === "number" >typeof x === "number" : boolean >typeof x : string ->x : number | string | boolean +>x : number | boolean >"number" : string && x); // x is number diff --git a/tests/baselines/reference/typeGuardsInDoStatement.js b/tests/baselines/reference/typeGuardsInDoStatement.js new file mode 100644 index 00000000000..7d299854f7d --- /dev/null +++ b/tests/baselines/reference/typeGuardsInDoStatement.js @@ -0,0 +1,60 @@ +//// [typeGuardsInDoStatement.ts] +let cond: boolean; +function a(x: string | number | boolean) { + x = true; + do { + x; // boolean | string + x = undefined; + } while (typeof x === "string") + x; // number | boolean +} +function b(x: string | number | boolean) { + x = true; + do { + x; // boolean | string + if (cond) continue; + x = undefined; + } while (typeof x === "string") + x; // number | boolean +} +function c(x: string | number) { + x = ""; + do { + x; // string + if (cond) break; + x = undefined; + } while (typeof x === "string") + x; // string | number +} + + +//// [typeGuardsInDoStatement.js] +var cond; +function a(x) { + x = true; + do { + x; // boolean | string + x = undefined; + } while (typeof x === "string"); + x; // number | boolean +} +function b(x) { + x = true; + do { + x; // boolean | string + if (cond) + continue; + x = undefined; + } while (typeof x === "string"); + x; // number | boolean +} +function c(x) { + x = ""; + do { + x; // string + if (cond) + break; + x = undefined; + } while (typeof x === "string"); + x; // string | number +} diff --git a/tests/baselines/reference/typeGuardsInDoStatement.symbols b/tests/baselines/reference/typeGuardsInDoStatement.symbols new file mode 100644 index 00000000000..7dff18d8d23 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInDoStatement.symbols @@ -0,0 +1,74 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardsInDoStatement.ts === +let cond: boolean; +>cond : Symbol(cond, Decl(typeGuardsInDoStatement.ts, 0, 3)) + +function a(x: string | number | boolean) { +>a : Symbol(a, Decl(typeGuardsInDoStatement.ts, 0, 18)) +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 1, 11)) + + x = true; +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 1, 11)) + + do { + x; // boolean | string +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 1, 11)) + + x = undefined; +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 1, 11)) +>undefined : Symbol(undefined) + + } while (typeof x === "string") +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 1, 11)) + + x; // number | boolean +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 1, 11)) +} +function b(x: string | number | boolean) { +>b : Symbol(b, Decl(typeGuardsInDoStatement.ts, 8, 1)) +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 9, 11)) + + x = true; +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 9, 11)) + + do { + x; // boolean | string +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 9, 11)) + + if (cond) continue; +>cond : Symbol(cond, Decl(typeGuardsInDoStatement.ts, 0, 3)) + + x = undefined; +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 9, 11)) +>undefined : Symbol(undefined) + + } while (typeof x === "string") +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 9, 11)) + + x; // number | boolean +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 9, 11)) +} +function c(x: string | number) { +>c : Symbol(c, Decl(typeGuardsInDoStatement.ts, 17, 1)) +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 18, 11)) + + x = ""; +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 18, 11)) + + do { + x; // string +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 18, 11)) + + if (cond) break; +>cond : Symbol(cond, Decl(typeGuardsInDoStatement.ts, 0, 3)) + + x = undefined; +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 18, 11)) +>undefined : Symbol(undefined) + + } while (typeof x === "string") +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 18, 11)) + + x; // string | number +>x : Symbol(x, Decl(typeGuardsInDoStatement.ts, 18, 11)) +} + diff --git a/tests/baselines/reference/typeGuardsInDoStatement.types b/tests/baselines/reference/typeGuardsInDoStatement.types new file mode 100644 index 00000000000..79183e7d6c8 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInDoStatement.types @@ -0,0 +1,92 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardsInDoStatement.ts === +let cond: boolean; +>cond : boolean + +function a(x: string | number | boolean) { +>a : (x: string | number | boolean) => void +>x : string | number | boolean + + x = true; +>x = true : boolean +>x : string | number | boolean +>true : boolean + + do { + x; // boolean | string +>x : boolean | string + + x = undefined; +>x = undefined : undefined +>x : string | number | boolean +>undefined : undefined + + } while (typeof x === "string") +>typeof x === "string" : boolean +>typeof x : string +>x : string | number | boolean +>"string" : string + + x; // number | boolean +>x : number | boolean +} +function b(x: string | number | boolean) { +>b : (x: string | number | boolean) => void +>x : string | number | boolean + + x = true; +>x = true : boolean +>x : string | number | boolean +>true : boolean + + do { + x; // boolean | string +>x : boolean | string + + if (cond) continue; +>cond : boolean + + x = undefined; +>x = undefined : undefined +>x : string | number | boolean +>undefined : undefined + + } while (typeof x === "string") +>typeof x === "string" : boolean +>typeof x : string +>x : string | number | boolean +>"string" : string + + x; // number | boolean +>x : number | boolean +} +function c(x: string | number) { +>c : (x: string | number) => void +>x : string | number + + x = ""; +>x = "" : string +>x : string | number +>"" : string + + do { + x; // string +>x : string + + if (cond) break; +>cond : boolean + + x = undefined; +>x = undefined : undefined +>x : string | number +>undefined : undefined + + } while (typeof x === "string") +>typeof x === "string" : boolean +>typeof x : string +>x : string | number +>"string" : string + + x; // string | number +>x : string | number +} + diff --git a/tests/baselines/reference/typeGuardsInForStatement.js b/tests/baselines/reference/typeGuardsInForStatement.js new file mode 100644 index 00000000000..a2e104bc3f1 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInForStatement.js @@ -0,0 +1,48 @@ +//// [typeGuardsInForStatement.ts] +let cond: boolean; +function a(x: string | number) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + } + x; // number +} +function b(x: string | number) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + if (cond) continue; + } + x; // number +} +function c(x: string | number) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + if (cond) break; + } + x; // string | number +} + + +//// [typeGuardsInForStatement.js] +var cond; +function a(x) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + } + x; // number +} +function b(x) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + if (cond) + continue; + } + x; // number +} +function c(x) { + for (x = undefined; typeof x !== "number"; x = undefined) { + x; // string + if (cond) + break; + } + x; // string | number +} diff --git a/tests/baselines/reference/typeGuardsInForStatement.symbols b/tests/baselines/reference/typeGuardsInForStatement.symbols new file mode 100644 index 00000000000..fe1c10eb14e --- /dev/null +++ b/tests/baselines/reference/typeGuardsInForStatement.symbols @@ -0,0 +1,62 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardsInForStatement.ts === +let cond: boolean; +>cond : Symbol(cond, Decl(typeGuardsInForStatement.ts, 0, 3)) + +function a(x: string | number) { +>a : Symbol(a, Decl(typeGuardsInForStatement.ts, 0, 18)) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 1, 11)) + + for (x = undefined; typeof x !== "number"; x = undefined) { +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 1, 11)) +>undefined : Symbol(undefined) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 1, 11)) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 1, 11)) +>undefined : Symbol(undefined) + + x; // string +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 1, 11)) + } + x; // number +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 1, 11)) +} +function b(x: string | number) { +>b : Symbol(b, Decl(typeGuardsInForStatement.ts, 6, 1)) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 7, 11)) + + for (x = undefined; typeof x !== "number"; x = undefined) { +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 7, 11)) +>undefined : Symbol(undefined) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 7, 11)) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 7, 11)) +>undefined : Symbol(undefined) + + x; // string +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 7, 11)) + + if (cond) continue; +>cond : Symbol(cond, Decl(typeGuardsInForStatement.ts, 0, 3)) + } + x; // number +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 7, 11)) +} +function c(x: string | number) { +>c : Symbol(c, Decl(typeGuardsInForStatement.ts, 13, 1)) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 14, 11)) + + for (x = undefined; typeof x !== "number"; x = undefined) { +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 14, 11)) +>undefined : Symbol(undefined) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 14, 11)) +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 14, 11)) +>undefined : Symbol(undefined) + + x; // string +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 14, 11)) + + if (cond) break; +>cond : Symbol(cond, Decl(typeGuardsInForStatement.ts, 0, 3)) + } + x; // string | number +>x : Symbol(x, Decl(typeGuardsInForStatement.ts, 14, 11)) +} + diff --git a/tests/baselines/reference/typeGuardsInForStatement.types b/tests/baselines/reference/typeGuardsInForStatement.types new file mode 100644 index 00000000000..5ebdea53c31 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInForStatement.types @@ -0,0 +1,77 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardsInForStatement.ts === +let cond: boolean; +>cond : boolean + +function a(x: string | number) { +>a : (x: string | number) => void +>x : string | number + + for (x = undefined; typeof x !== "number"; x = undefined) { +>x = undefined : undefined +>x : string | number +>undefined : undefined +>typeof x !== "number" : boolean +>typeof x : string +>x : string | number +>"number" : string +>x = undefined : undefined +>x : string | number +>undefined : undefined + + x; // string +>x : string + } + x; // number +>x : number +} +function b(x: string | number) { +>b : (x: string | number) => void +>x : string | number + + for (x = undefined; typeof x !== "number"; x = undefined) { +>x = undefined : undefined +>x : string | number +>undefined : undefined +>typeof x !== "number" : boolean +>typeof x : string +>x : string | number +>"number" : string +>x = undefined : undefined +>x : string | number +>undefined : undefined + + x; // string +>x : string + + if (cond) continue; +>cond : boolean + } + x; // number +>x : number +} +function c(x: string | number) { +>c : (x: string | number) => void +>x : string | number + + for (x = undefined; typeof x !== "number"; x = undefined) { +>x = undefined : undefined +>x : string | number +>undefined : undefined +>typeof x !== "number" : boolean +>typeof x : string +>x : string | number +>"number" : string +>x = undefined : undefined +>x : string | number +>undefined : undefined + + x; // string +>x : string + + if (cond) break; +>cond : boolean + } + x; // string | number +>x : number | string +} + diff --git a/tests/baselines/reference/typeGuardsInIfStatement.errors.txt b/tests/baselines/reference/typeGuardsInIfStatement.errors.txt new file mode 100644 index 00000000000..984ca454e76 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInIfStatement.errors.txt @@ -0,0 +1,153 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts(22,10): error TS2354: No best common type exists among return expressions. +tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts(31,10): error TS2354: No best common type exists among return expressions. +tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts(49,10): error TS2354: No best common type exists among return expressions. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts (3 errors) ==== + // In the true branch statement of an 'if' statement, + // the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true. + // In the false branch statement of an 'if' statement, + // the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false. + function foo(x: number | string) { + if (typeof x === "string") { + return x.length; // string + } + else { + return x++; // number + } + } + function foo2(x: number | string) { + if (typeof x === "string") { + x = 10; + return x; // number + } + else { + return x; // number + } + } + function foo3(x: number | string) { + ~~~~ +!!! error TS2354: No best common type exists among return expressions. + if (typeof x === "string") { + x = "Hello"; + return x; // string + } + else { + return x; // number + } + } + function foo4(x: number | string) { + ~~~~ +!!! error TS2354: No best common type exists among return expressions. + if (typeof x === "string") { + return x; // string + } + else { + x = 10; + return x; // number + } + } + function foo5(x: number | string) { + if (typeof x === "string") { + return x; // string + } + else { + x = "hello"; + return x; // string + } + } + function foo6(x: number | string) { + ~~~~ +!!! error TS2354: No best common type exists among return expressions. + if (typeof x === "string") { + x = 10; + return x; // number + } + else { + x = "hello"; + return x; // string + } + } + function foo7(x: number | string | boolean) { + if (typeof x === "string") { + return x === "hello"; // string + } + else if (typeof x === "boolean") { + return x; // boolean + } + else { + return x == 10; // number + } + } + function foo8(x: number | string | boolean) { + if (typeof x === "string") { + return x === "hello"; // string + } + else { + var b: number | boolean = x; // number | boolean + if (typeof x === "boolean") { + return x; // boolean + } + else { + return x == 10; // number + } + } + } + function foo9(x: number | string) { + var y = 10; + if (typeof x === "string") { + // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop + y = x.length; + return x === "hello"; // string + } + else { + return x == 10; // number + } + } + function foo10(x: number | string | boolean) { + // Mixing typeguard narrowing in if statement with conditional expression typeguard + if (typeof x === "string") { + return x === "hello"; // string + } + else { + var y: boolean | string; + var b = x; // number | boolean + return typeof x === "number" + ? x === 10 // number + : x; // x should be boolean + } + } + function foo11(x: number | string | boolean) { + // Mixing typeguard narrowing in if statement with conditional expression typeguard + // Assigning value to x deep inside another guard stops narrowing of type too + if (typeof x === "string") { + return x; // string | number | boolean - x changed in else branch + } + else { + var y: number| boolean | string; + var b = x; // number | boolean | string - because below we are changing value of x in if statement + return typeof x === "number" + ? ( + // change value of x + x = 10 && x.toString() // number | boolean | string + ) + : ( + // do not change value + y = x && x.toString() // number | boolean | string + ); + } + } + function foo12(x: number | string | boolean) { + // Mixing typeguard narrowing in if statement with conditional expression typeguard + // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression + if (typeof x === "string") { + return x.toString(); // string | number | boolean - x changed in else branch + } + else { + x = 10; + var b = x; // number | boolean | string + return typeof x === "number" + ? x.toString() // number + : x.toString(); // boolean | string + } + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsInIfStatement.js b/tests/baselines/reference/typeGuardsInIfStatement.js index de05a7bf82a..8e841d2eac3 100644 --- a/tests/baselines/reference/typeGuardsInIfStatement.js +++ b/tests/baselines/reference/typeGuardsInIfStatement.js @@ -1,10 +1,8 @@ //// [typeGuardsInIfStatement.ts] // In the true branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true, -// provided the true branch statement contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true. // In the false branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false, -// provided the false branch statement contains no assignments to the variable or parameter +// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false. function foo(x: number | string) { if (typeof x === "string") { return x.length; // string @@ -14,54 +12,49 @@ function foo(x: number | string) { } } function foo2(x: number | string) { - // x is assigned in the if true branch, the type is not narrowed if (typeof x === "string") { x = 10; - return x; // string | number + return x; // number } else { - return x; // string | number + return x; // number } } function foo3(x: number | string) { - // x is assigned in the if true branch, the type is not narrowed if (typeof x === "string") { - x = "Hello"; // even though assigned using same type as narrowed expression - return x; // string | number + x = "Hello"; + return x; // string } else { - return x; // string | number + return x; // number } } function foo4(x: number | string) { - // false branch updates the variable - so here it is not number if (typeof x === "string") { - return x; // string | number + return x; // string } else { - x = 10; // even though assigned number - this should result in x to be string | number - return x; // string | number + x = 10; + return x; // number } } function foo5(x: number | string) { - // false branch updates the variable - so here it is not number if (typeof x === "string") { - return x; // string | number + return x; // string } else { x = "hello"; - return x; // string | number + return x; // string } } function foo6(x: number | string) { - // Modify in both branches if (typeof x === "string") { x = 10; - return x; // string | number + return x; // number } else { x = "hello"; - return x; // string | number + return x; // string } } function foo7(x: number | string | boolean) { @@ -150,11 +143,9 @@ function foo12(x: number | string | boolean) { //// [typeGuardsInIfStatement.js] // In the true branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true, -// provided the true branch statement contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true. // In the false branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false, -// provided the false branch statement contains no assignments to the variable or parameter +// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false. function foo(x) { if (typeof x === "string") { return x.length; // string @@ -164,54 +155,49 @@ function foo(x) { } } function foo2(x) { - // x is assigned in the if true branch, the type is not narrowed if (typeof x === "string") { x = 10; - return x; // string | number + return x; // number } else { - return x; // string | number + return x; // number } } function foo3(x) { - // x is assigned in the if true branch, the type is not narrowed if (typeof x === "string") { - x = "Hello"; // even though assigned using same type as narrowed expression - return x; // string | number + x = "Hello"; + return x; // string } else { - return x; // string | number + return x; // number } } function foo4(x) { - // false branch updates the variable - so here it is not number if (typeof x === "string") { - return x; // string | number + return x; // string } else { - x = 10; // even though assigned number - this should result in x to be string | number - return x; // string | number + x = 10; + return x; // number } } function foo5(x) { - // false branch updates the variable - so here it is not number if (typeof x === "string") { - return x; // string | number + return x; // string } else { x = "hello"; - return x; // string | number + return x; // string } } function foo6(x) { - // Modify in both branches if (typeof x === "string") { x = 10; - return x; // string | number + return x; // number } else { x = "hello"; - return x; // string | number + return x; // string } } function foo7(x) { diff --git a/tests/baselines/reference/typeGuardsInIfStatement.symbols b/tests/baselines/reference/typeGuardsInIfStatement.symbols deleted file mode 100644 index 54a65f0693b..00000000000 --- a/tests/baselines/reference/typeGuardsInIfStatement.symbols +++ /dev/null @@ -1,304 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts === -// In the true branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true, -// provided the true branch statement contains no assignments to the variable or parameter. -// In the false branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false, -// provided the false branch statement contains no assignments to the variable or parameter -function foo(x: number | string) { ->foo : Symbol(foo, Decl(typeGuardsInIfStatement.ts, 0, 0)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13)) - - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13)) - - return x.length; // string ->x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13)) ->length : Symbol(String.length, Decl(lib.d.ts, --, --)) - } - else { - return x++; // number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13)) - } -} -function foo2(x: number | string) { ->foo2 : Symbol(foo2, Decl(typeGuardsInIfStatement.ts, 13, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14)) - - // x is assigned in the if true branch, the type is not narrowed - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14)) - - x = 10; ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14)) - } - else { - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14)) - } -} -function foo3(x: number | string) { ->foo3 : Symbol(foo3, Decl(typeGuardsInIfStatement.ts, 23, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14)) - - // x is assigned in the if true branch, the type is not narrowed - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14)) - - x = "Hello"; // even though assigned using same type as narrowed expression ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14)) - } - else { - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14)) - } -} -function foo4(x: number | string) { ->foo4 : Symbol(foo4, Decl(typeGuardsInIfStatement.ts, 33, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14)) - - // false branch updates the variable - so here it is not number - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14)) - } - else { - x = 10; // even though assigned number - this should result in x to be string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14)) - } -} -function foo5(x: number | string) { ->foo5 : Symbol(foo5, Decl(typeGuardsInIfStatement.ts, 43, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14)) - - // false branch updates the variable - so here it is not number - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14)) - } - else { - x = "hello"; ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14)) - } -} -function foo6(x: number | string) { ->foo6 : Symbol(foo6, Decl(typeGuardsInIfStatement.ts, 53, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14)) - - // Modify in both branches - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14)) - - x = 10; ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14)) - } - else { - x = "hello"; ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14)) - - return x; // string | number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14)) - } -} -function foo7(x: number | string | boolean) { ->foo7 : Symbol(foo7, Decl(typeGuardsInIfStatement.ts, 64, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14)) - - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14)) - - return x === "hello"; // string ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14)) - } - else if (typeof x === "boolean") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14)) - - return x; // boolean ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14)) - } - else { - return x == 10; // number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14)) - } -} -function foo8(x: number | string | boolean) { ->foo8 : Symbol(foo8, Decl(typeGuardsInIfStatement.ts, 75, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14)) - - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14)) - - return x === "hello"; // string ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14)) - } - else { - var b: number | boolean = x; // number | boolean ->b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 81, 11)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14)) - - if (typeof x === "boolean") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14)) - - return x; // boolean ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14)) - } - else { - return x == 10; // number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14)) - } - } -} -function foo9(x: number | string) { ->foo9 : Symbol(foo9, Decl(typeGuardsInIfStatement.ts, 89, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14)) - - var y = 10; ->y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 91, 7)) - - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14)) - - // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop - y = x.length; ->y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 91, 7)) ->x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14)) ->length : Symbol(String.length, Decl(lib.d.ts, --, --)) - - return x === "hello"; // string ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14)) - } - else { - return x == 10; // number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14)) - } -} -function foo10(x: number | string | boolean) { ->foo10 : Symbol(foo10, Decl(typeGuardsInIfStatement.ts, 100, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15)) - - // Mixing typeguard narrowing in if statement with conditional expression typeguard - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15)) - - return x === "hello"; // string ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15)) - } - else { - var y: boolean | string; ->y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 107, 11)) - - var b = x; // number | boolean ->b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 108, 11)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15)) - - return typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15)) - - ? x === 10 // number ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15)) - - : x; // x should be boolean ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15)) - } -} -function foo11(x: number | string | boolean) { ->foo11 : Symbol(foo11, Decl(typeGuardsInIfStatement.ts, 113, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) - - // Mixing typeguard narrowing in if statement with conditional expression typeguard - // Assigning value to x deep inside another guard stops narrowing of type too - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) - - return x; // string | number | boolean - x changed in else branch ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) - } - else { - var y: number| boolean | string; ->y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 121, 11)) - - var b = x; // number | boolean | string - because below we are changing value of x in if statement ->b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 122, 11)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) - - return typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) - - ? ( - // change value of x - x = 10 && x.toString() // number | boolean | string ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) - - ) - : ( - // do not change value - y = x && x.toString() // number | boolean | string ->y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 121, 11)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) - - ); - } -} -function foo12(x: number | string | boolean) { ->foo12 : Symbol(foo12, Decl(typeGuardsInIfStatement.ts, 133, 1)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) - - // Mixing typeguard narrowing in if statement with conditional expression typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - if (typeof x === "string") { ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) - - return x.toString(); // string | number | boolean - x changed in else branch ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) - } - else { - x = 10; ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) - - var b = x; // number | boolean | string ->b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 142, 11)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) - - return typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) - - ? x.toString() // number ->x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) ->toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) - - : x.toString(); // boolean | string ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) - } -} diff --git a/tests/baselines/reference/typeGuardsInIfStatement.types b/tests/baselines/reference/typeGuardsInIfStatement.types deleted file mode 100644 index 0095a7cc768..00000000000 --- a/tests/baselines/reference/typeGuardsInIfStatement.types +++ /dev/null @@ -1,405 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts === -// In the true branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when true, -// provided the true branch statement contains no assignments to the variable or parameter. -// In the false branch statement of an 'if' statement, -// the type of a variable or parameter is narrowed by any type guard in the 'if' condition when false, -// provided the false branch statement contains no assignments to the variable or parameter -function foo(x: number | string) { ->foo : (x: number | string) => number ->x : number | string - - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - return x.length; // string ->x.length : number ->x : string ->length : number - } - else { - return x++; // number ->x++ : number ->x : number - } -} -function foo2(x: number | string) { ->foo2 : (x: number | string) => number | string ->x : number | string - - // x is assigned in the if true branch, the type is not narrowed - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - x = 10; ->x = 10 : number ->x : number | string ->10 : number - - return x; // string | number ->x : number | string - } - else { - return x; // string | number ->x : number | string - } -} -function foo3(x: number | string) { ->foo3 : (x: number | string) => number | string ->x : number | string - - // x is assigned in the if true branch, the type is not narrowed - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - x = "Hello"; // even though assigned using same type as narrowed expression ->x = "Hello" : string ->x : number | string ->"Hello" : string - - return x; // string | number ->x : number | string - } - else { - return x; // string | number ->x : number | string - } -} -function foo4(x: number | string) { ->foo4 : (x: number | string) => number | string ->x : number | string - - // false branch updates the variable - so here it is not number - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - return x; // string | number ->x : number | string - } - else { - x = 10; // even though assigned number - this should result in x to be string | number ->x = 10 : number ->x : number | string ->10 : number - - return x; // string | number ->x : number | string - } -} -function foo5(x: number | string) { ->foo5 : (x: number | string) => number | string ->x : number | string - - // false branch updates the variable - so here it is not number - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - return x; // string | number ->x : number | string - } - else { - x = "hello"; ->x = "hello" : string ->x : number | string ->"hello" : string - - return x; // string | number ->x : number | string - } -} -function foo6(x: number | string) { ->foo6 : (x: number | string) => number | string ->x : number | string - - // Modify in both branches - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - x = 10; ->x = 10 : number ->x : number | string ->10 : number - - return x; // string | number ->x : number | string - } - else { - x = "hello"; ->x = "hello" : string ->x : number | string ->"hello" : string - - return x; // string | number ->x : number | string - } -} -function foo7(x: number | string | boolean) { ->foo7 : (x: number | string | boolean) => boolean ->x : number | string | boolean - - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string | boolean ->"string" : string - - return x === "hello"; // string ->x === "hello" : boolean ->x : string ->"hello" : string - } - else if (typeof x === "boolean") { ->typeof x === "boolean" : boolean ->typeof x : string ->x : number | boolean ->"boolean" : string - - return x; // boolean ->x : boolean - } - else { - return x == 10; // number ->x == 10 : boolean ->x : number ->10 : number - } -} -function foo8(x: number | string | boolean) { ->foo8 : (x: number | string | boolean) => boolean ->x : number | string | boolean - - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string | boolean ->"string" : string - - return x === "hello"; // string ->x === "hello" : boolean ->x : string ->"hello" : string - } - else { - var b: number | boolean = x; // number | boolean ->b : number | boolean ->x : number | boolean - - if (typeof x === "boolean") { ->typeof x === "boolean" : boolean ->typeof x : string ->x : number | boolean ->"boolean" : string - - return x; // boolean ->x : boolean - } - else { - return x == 10; // number ->x == 10 : boolean ->x : number ->10 : number - } - } -} -function foo9(x: number | string) { ->foo9 : (x: number | string) => boolean ->x : number | string - - var y = 10; ->y : number ->10 : number - - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop - y = x.length; ->y = x.length : number ->y : number ->x.length : number ->x : string ->length : number - - return x === "hello"; // string ->x === "hello" : boolean ->x : string ->"hello" : string - } - else { - return x == 10; // number ->x == 10 : boolean ->x : number ->10 : number - } -} -function foo10(x: number | string | boolean) { ->foo10 : (x: number | string | boolean) => boolean ->x : number | string | boolean - - // Mixing typeguard narrowing in if statement with conditional expression typeguard - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string | boolean ->"string" : string - - return x === "hello"; // string ->x === "hello" : boolean ->x : string ->"hello" : string - } - else { - var y: boolean | string; ->y : boolean | string - - var b = x; // number | boolean ->b : number | boolean ->x : number | boolean - - return typeof x === "number" ->typeof x === "number" ? x === 10 // number : x : boolean ->typeof x === "number" : boolean ->typeof x : string ->x : number | boolean ->"number" : string - - ? x === 10 // number ->x === 10 : boolean ->x : number ->10 : number - - : x; // x should be boolean ->x : boolean - } -} -function foo11(x: number | string | boolean) { ->foo11 : (x: number | string | boolean) => number | string | boolean ->x : number | string | boolean - - // Mixing typeguard narrowing in if statement with conditional expression typeguard - // Assigning value to x deep inside another guard stops narrowing of type too - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string | boolean ->"string" : string - - return x; // string | number | boolean - x changed in else branch ->x : number | string | boolean - } - else { - var y: number| boolean | string; ->y : number | boolean | string - - var b = x; // number | boolean | string - because below we are changing value of x in if statement ->b : number | string | boolean ->x : number | string | boolean - - return typeof x === "number" ->typeof x === "number" ? ( // change value of x x = 10 && x.toString() // number | boolean | string ) : ( // do not change value y = x && x.toString() // number | boolean | string ) : string ->typeof x === "number" : boolean ->typeof x : string ->x : number | string | boolean ->"number" : string - - ? ( ->( // change value of x x = 10 && x.toString() // number | boolean | string ) : string - - // change value of x - x = 10 && x.toString() // number | boolean | string ->x = 10 && x.toString() : string ->x : number | string | boolean ->10 && x.toString() : string ->10 : number ->x.toString() : string ->x.toString : (radix?: number) => string ->x : number | string | boolean ->toString : (radix?: number) => string - - ) - : ( ->( // do not change value y = x && x.toString() // number | boolean | string ) : string - - // do not change value - y = x && x.toString() // number | boolean | string ->y = x && x.toString() : string ->y : number | boolean | string ->x && x.toString() : string ->x : number | string | boolean ->x.toString() : string ->x.toString : (radix?: number) => string ->x : number | string | boolean ->toString : (radix?: number) => string - - ); - } -} -function foo12(x: number | string | boolean) { ->foo12 : (x: number | string | boolean) => string ->x : number | string | boolean - - // Mixing typeguard narrowing in if statement with conditional expression typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - if (typeof x === "string") { ->typeof x === "string" : boolean ->typeof x : string ->x : number | string | boolean ->"string" : string - - return x.toString(); // string | number | boolean - x changed in else branch ->x.toString() : string ->x.toString : (radix?: number) => string ->x : number | string | boolean ->toString : (radix?: number) => string - } - else { - x = 10; ->x = 10 : number ->x : number | string | boolean ->10 : number - - var b = x; // number | boolean | string ->b : number | string | boolean ->x : number | string | boolean - - return typeof x === "number" ->typeof x === "number" ? x.toString() // number : x.toString() : string ->typeof x === "number" : boolean ->typeof x : string ->x : number | string | boolean ->"number" : string - - ? x.toString() // number ->x.toString() : string ->x.toString : (radix?: number) => string ->x : number ->toString : (radix?: number) => string - - : x.toString(); // boolean | string ->x.toString() : string ->x.toString : () => string ->x : string | boolean ->toString : () => string - } -} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js index e3f1a8c72c2..be1c497e3ea 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js +++ b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js @@ -1,7 +1,6 @@ //// [typeGuardsInRightOperandOfAndAndOperator.ts] // In the right operand of a && operation, -// the type of a variable or parameter is narrowed by any type guard in the left operand when true, -// provided the right operand contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the left operand when true. function foo(x: number | string) { return typeof x === "string" && x.length === 10; // string } @@ -36,29 +35,19 @@ function foo7(x: number | string | boolean) { var y: number| boolean | string; var z: number| boolean | string; // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x !== "string" - && ((z = x) // string | number | boolean - x changed deeper in conditional expression + && ((z = x) // number | boolean && (typeof x === "number" // change value of x - ? (x = 10 && x.toString()) // number | boolean | string + ? ((x = 10) && x.toString()) // x is number // do not change value - : (y = x && x.toString()))); // number | boolean | string + : ((y = x) && x.toString()))); // x is boolean } -function foo8(x: number | string) { - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x !== "string" - && (x = 10) // change x - number| string - && (typeof x === "number" - ? x // number - : x.length); // string -} + //// [typeGuardsInRightOperandOfAndAndOperator.js] // In the right operand of a && operation, -// the type of a variable or parameter is narrowed by any type guard in the left operand when true, -// provided the right operand contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the left operand when true. function foo(x) { return typeof x === "string" && x.length === 10; // string } @@ -93,19 +82,9 @@ function foo7(x) { var y; var z; // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x !== "string" - && ((z = x) // string | number | boolean - x changed deeper in conditional expression + && ((z = x) // number | boolean && (typeof x === "number" - ? (x = 10 && x.toString()) // number | boolean | string - : (y = x && x.toString()))); // number | boolean | string -} -function foo8(x) { - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x !== "string" - && (x = 10) // change x - number| string - && (typeof x === "number" - ? x // number - : x.length); // string + ? ((x = 10) && x.toString()) // x is number + : ((y = x) && x.toString()))); // x is boolean } diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.symbols b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.symbols index 21e3dd3701f..4028edb6b42 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.symbols +++ b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.symbols @@ -1,143 +1,119 @@ === tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts === // In the right operand of a && operation, -// the type of a variable or parameter is narrowed by any type guard in the left operand when true, -// provided the right operand contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the left operand when true. function foo(x: number | string) { >foo : Symbol(foo, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 0, 0)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 3, 13)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 2, 13)) return typeof x === "string" && x.length === 10; // string ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 3, 13)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 2, 13)) >x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 3, 13)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 2, 13)) >length : Symbol(String.length, Decl(lib.d.ts, --, --)) } function foo2(x: number | string) { ->foo2 : Symbol(foo2, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 5, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14)) +>foo2 : Symbol(foo2, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 4, 1)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 5, 14)) // modify x in right hand operand return typeof x === "string" && ((x = 10) && x); // string | number ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 5, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 5, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 5, 14)) } function foo3(x: number | string) { ->foo3 : Symbol(foo3, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 9, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14)) +>foo3 : Symbol(foo3, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 8, 1)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 9, 14)) // modify x in right hand operand with string type itself return typeof x === "string" && ((x = "hello") && x); // string | number ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 9, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 9, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 9, 14)) } function foo4(x: number | string | boolean) { ->foo4 : Symbol(foo4, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 13, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14)) +>foo4 : Symbol(foo4, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 12, 1)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 13, 14)) return typeof x !== "string" // string | number | boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 13, 14)) && typeof x !== "number" // number | boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 13, 14)) && x; // boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 13, 14)) } function foo5(x: number | string | boolean) { ->foo5 : Symbol(foo5, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 18, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14)) +>foo5 : Symbol(foo5, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 17, 1)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 18, 14)) // usage of x or assignment to separate variable shouldn't cause narrowing of type to stop var b: number | boolean; ->b : Symbol(b, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 21, 7)) +>b : Symbol(b, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 20, 7)) return typeof x !== "string" // string | number | boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 18, 14)) && ((b = x) && (typeof x !== "number" // number | boolean ->b : Symbol(b, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 21, 7)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14)) +>b : Symbol(b, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 20, 7)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 18, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 18, 14)) && x)); // boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 18, 14)) } function foo6(x: number | string | boolean) { ->foo6 : Symbol(foo6, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 25, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14)) +>foo6 : Symbol(foo6, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 24, 1)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 25, 14)) // Mixing typeguard narrowing in if statement with conditional expression typeguard return typeof x !== "string" // string | number | boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 25, 14)) && (typeof x !== "number" // number | boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 25, 14)) ? x // boolean ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 25, 14)) : x === 10) // number ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 25, 14)) } function foo7(x: number | string | boolean) { ->foo7 : Symbol(foo7, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) +>foo7 : Symbol(foo7, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 31, 1)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) var y: number| boolean | string; ->y : Symbol(y, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 34, 7)) +>y : Symbol(y, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 7)) var z: number| boolean | string; ->z : Symbol(z, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 35, 7)) +>z : Symbol(z, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 34, 7)) // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x !== "string" ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) - && ((z = x) // string | number | boolean - x changed deeper in conditional expression ->z : Symbol(z, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 35, 7)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) + && ((z = x) // number | boolean +>z : Symbol(z, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 34, 7)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) && (typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) // change value of x - ? (x = 10 && x.toString()) // number | boolean | string ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + ? ((x = 10) && x.toString()) // x is number +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) +>x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) // do not change value - : (y = x && x.toString()))); // number | boolean | string ->y : Symbol(y, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 34, 7)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + : ((y = x) && x.toString()))); // x is boolean +>y : Symbol(y, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 7)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) +>x.toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 14)) +>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) } -function foo8(x: number | string) { ->foo8 : Symbol(foo8, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 45, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14)) - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x !== "string" ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14)) - - && (x = 10) // change x - number| string ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14)) - - && (typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14)) - - ? x // number ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14)) - - : x.length); // string ->x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14)) ->length : Symbol(String.length, Decl(lib.d.ts, --, --)) -} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types index 22d390618c1..2da52b8b1b8 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types +++ b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types @@ -1,7 +1,6 @@ === tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts === // In the right operand of a && operation, -// the type of a variable or parameter is narrowed by any type guard in the left operand when true, -// provided the right operand contains no assignments to the variable or parameter. +// the type of a variable or parameter is narrowed by any type guard in the left operand when true. function foo(x: number | string) { >foo : (x: number | string) => boolean >x : number | string @@ -19,42 +18,42 @@ function foo(x: number | string) { >10 : number } function foo2(x: number | string) { ->foo2 : (x: number | string) => number | string +>foo2 : (x: number | string) => number >x : number | string // modify x in right hand operand return typeof x === "string" && ((x = 10) && x); // string | number ->typeof x === "string" && ((x = 10) && x) : number | string +>typeof x === "string" && ((x = 10) && x) : number >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string ->((x = 10) && x) : number | string ->(x = 10) && x : number | string +>((x = 10) && x) : number +>(x = 10) && x : number >(x = 10) : number >x = 10 : number >x : number | string >10 : number ->x : number | string +>x : number } function foo3(x: number | string) { ->foo3 : (x: number | string) => number | string +>foo3 : (x: number | string) => string >x : number | string // modify x in right hand operand with string type itself return typeof x === "string" && ((x = "hello") && x); // string | number ->typeof x === "string" && ((x = "hello") && x) : number | string +>typeof x === "string" && ((x = "hello") && x) : string >typeof x === "string" : boolean >typeof x : string >x : number | string >"string" : string ->((x = "hello") && x) : number | string ->(x = "hello") && x : number | string +>((x = "hello") && x) : string +>(x = "hello") && x : string >(x = "hello") : string >x = "hello" : string >x : number | string >"hello" : string ->x : number | string +>x : string } function foo4(x: number | string | boolean) { >foo4 : (x: number | string | boolean) => boolean @@ -148,87 +147,53 @@ function foo7(x: number | string | boolean) { >z : number | boolean | string // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x !== "string" ->typeof x !== "string" && ((z = x) // string | number | boolean - x changed deeper in conditional expression && (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : string +>typeof x !== "string" && ((z = x) // number | boolean && (typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // x is number // do not change value : ((y = x) && x.toString()))) : string >typeof x !== "string" : boolean >typeof x : string >x : number | string | boolean >"string" : string - && ((z = x) // string | number | boolean - x changed deeper in conditional expression ->((z = x) // string | number | boolean - x changed deeper in conditional expression && (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : string ->(z = x) // string | number | boolean - x changed deeper in conditional expression && (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string ->(z = x) : number | string | boolean ->z = x : number | string | boolean + && ((z = x) // number | boolean +>((z = x) // number | boolean && (typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // x is number // do not change value : ((y = x) && x.toString()))) : string +>(z = x) // number | boolean && (typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // x is number // do not change value : ((y = x) && x.toString())) : string +>(z = x) : number | boolean +>z = x : number | boolean >z : number | boolean | string ->x : number | string | boolean +>x : number | boolean && (typeof x === "number" ->(typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string ->typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()) : string +>(typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // x is number // do not change value : ((y = x) && x.toString())) : string +>typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // x is number // do not change value : ((y = x) && x.toString()) : string >typeof x === "number" : boolean >typeof x : string ->x : number | string | boolean +>x : number | boolean >"number" : string // change value of x - ? (x = 10 && x.toString()) // number | boolean | string ->(x = 10 && x.toString()) : string ->x = 10 && x.toString() : string + ? ((x = 10) && x.toString()) // x is number +>((x = 10) && x.toString()) : string +>(x = 10) && x.toString() : string +>(x = 10) : number +>x = 10 : number >x : number | string | boolean ->10 && x.toString() : string >10 : number >x.toString() : string >x.toString : (radix?: number) => string ->x : number | string | boolean +>x : number >toString : (radix?: number) => string // do not change value - : (y = x && x.toString()))); // number | boolean | string ->(y = x && x.toString()) : string ->y = x && x.toString() : string + : ((y = x) && x.toString()))); // x is boolean +>((y = x) && x.toString()) : string +>(y = x) && x.toString() : string +>(y = x) : boolean +>y = x : boolean >y : number | boolean | string ->x && x.toString() : string ->x : number | string | boolean +>x : boolean >x.toString() : string ->x.toString : (radix?: number) => string ->x : number | string | boolean ->toString : (radix?: number) => string +>x.toString : () => string +>x : boolean +>toString : () => string } -function foo8(x: number | string) { ->foo8 : (x: number | string) => number ->x : number | string - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x !== "string" ->typeof x !== "string" && (x = 10) // change x - number| string && (typeof x === "number" ? x // number : x.length) : number ->typeof x !== "string" && (x = 10) : number ->typeof x !== "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - && (x = 10) // change x - number| string ->(x = 10) : number ->x = 10 : number ->x : number | string ->10 : number - - && (typeof x === "number" ->(typeof x === "number" ? x // number : x.length) : number ->typeof x === "number" ? x // number : x.length : number ->typeof x === "number" : boolean ->typeof x : string ->x : number | string ->"number" : string - - ? x // number ->x : number - - : x.length); // string ->x.length : number ->x : string ->length : number -} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js index 188d226da13..a8d66dc5fa2 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js +++ b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js @@ -36,24 +36,15 @@ function foo7(x: number | string | boolean) { var y: number| boolean | string; var z: number| boolean | string; // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x === "string" - || ((z = x) // string | number | boolean - x changed deeper in conditional expression + || ((z = x) // number | boolean || (typeof x === "number" // change value of x - ? (x = 10 && x.toString()) // number | boolean | string + ? ((x = 10) && x.toString()) // number | boolean | string // do not change value - : (y = x && x.toString()))); // number | boolean | string + : ((y = x) && x.toString()))); // number | boolean | string } -function foo8(x: number | string) { - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x === "string" - || (x = 10) // change x - number| string - || (typeof x === "number" - ? x // number - : x.length); // string -} + //// [typeGuardsInRightOperandOfOrOrOperator.js] // In the right operand of a || operation, @@ -93,19 +84,9 @@ function foo7(x) { var y; var z; // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x === "string" - || ((z = x) // string | number | boolean - x changed deeper in conditional expression + || ((z = x) // number | boolean || (typeof x === "number" - ? (x = 10 && x.toString()) // number | boolean | string - : (y = x && x.toString()))); // number | boolean | string -} -function foo8(x) { - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x === "string" - || (x = 10) // change x - number| string - || (typeof x === "number" - ? x // number - : x.length); // string + ? ((x = 10) && x.toString()) // number | boolean | string + : ((y = x) && x.toString()))); // number | boolean | string } diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.symbols b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.symbols index de9b4396d3d..b276671819a 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.symbols +++ b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.symbols @@ -92,11 +92,10 @@ function foo7(x: number | string | boolean) { >z : Symbol(z, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 35, 7)) // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x === "string" >x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14)) - || ((z = x) // string | number | boolean - x changed deeper in conditional expression + || ((z = x) // number | boolean >z : Symbol(z, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 35, 7)) >x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14)) @@ -104,40 +103,18 @@ function foo7(x: number | string | boolean) { >x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14)) // change value of x - ? (x = 10 && x.toString()) // number | boolean | string + ? ((x = 10) && x.toString()) // number | boolean | string >x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14)) ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) >x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) // do not change value - : (y = x && x.toString()))); // number | boolean | string + : ((y = x) && x.toString()))); // number | boolean | string >y : Symbol(y, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 34, 7)) >x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14)) ->x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>x.toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) >x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14)) ->toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) } -function foo8(x: number | string) { ->foo8 : Symbol(foo8, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 45, 1)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14)) - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x === "string" ->x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14)) - - || (x = 10) // change x - number| string ->x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14)) - - || (typeof x === "number" ->x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14)) - - ? x // number ->x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14)) - - : x.length); // string ->x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14)) ->length : Symbol(String.length, Decl(lib.d.ts, --, --)) -} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types index 38d9a723d3a..659182ab888 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types +++ b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types @@ -19,42 +19,42 @@ function foo(x: number | string) { >10 : number } function foo2(x: number | string) { ->foo2 : (x: number | string) => boolean | number | string +>foo2 : (x: number | string) => boolean | number >x : number | string // modify x in right hand operand return typeof x !== "string" || ((x = 10) || x); // string | number ->typeof x !== "string" || ((x = 10) || x) : boolean | number | string +>typeof x !== "string" || ((x = 10) || x) : boolean | number >typeof x !== "string" : boolean >typeof x : string >x : number | string >"string" : string ->((x = 10) || x) : number | string ->(x = 10) || x : number | string +>((x = 10) || x) : number +>(x = 10) || x : number >(x = 10) : number >x = 10 : number >x : number | string >10 : number ->x : number | string +>x : number } function foo3(x: number | string) { ->foo3 : (x: number | string) => boolean | string | number +>foo3 : (x: number | string) => boolean | string >x : number | string // modify x in right hand operand with string type itself return typeof x !== "string" || ((x = "hello") || x); // string | number ->typeof x !== "string" || ((x = "hello") || x) : boolean | string | number +>typeof x !== "string" || ((x = "hello") || x) : boolean | string >typeof x !== "string" : boolean >typeof x : string >x : number | string >"string" : string ->((x = "hello") || x) : string | number ->(x = "hello") || x : string | number +>((x = "hello") || x) : string +>(x = "hello") || x : string >(x = "hello") : string >x = "hello" : string >x : number | string >"hello" : string ->x : number | string +>x : string } function foo4(x: number | string | boolean) { >foo4 : (x: number | string | boolean) => boolean @@ -148,87 +148,53 @@ function foo7(x: number | string | boolean) { >z : number | boolean | string // Mixing typeguard narrowing - // Assigning value to x deep inside another guard stops narrowing of type too return typeof x === "string" ->typeof x === "string" || ((z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : boolean | number | string +>typeof x === "string" || ((z = x) // number | boolean || (typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // number | boolean | string // do not change value : ((y = x) && x.toString()))) : boolean | number | string >typeof x === "string" : boolean >typeof x : string >x : number | string | boolean >"string" : string - || ((z = x) // string | number | boolean - x changed deeper in conditional expression ->((z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : number | string | boolean ->(z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : number | string | boolean ->(z = x) : number | string | boolean ->z = x : number | string | boolean + || ((z = x) // number | boolean +>((z = x) // number | boolean || (typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // number | boolean | string // do not change value : ((y = x) && x.toString()))) : number | boolean | string +>(z = x) // number | boolean || (typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // number | boolean | string // do not change value : ((y = x) && x.toString())) : number | boolean | string +>(z = x) : number | boolean +>z = x : number | boolean >z : number | boolean | string ->x : number | string | boolean +>x : number | boolean || (typeof x === "number" ->(typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string ->typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()) : string +>(typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // number | boolean | string // do not change value : ((y = x) && x.toString())) : string +>typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // number | boolean | string // do not change value : ((y = x) && x.toString()) : string >typeof x === "number" : boolean >typeof x : string ->x : number | string | boolean +>x : number | boolean >"number" : string // change value of x - ? (x = 10 && x.toString()) // number | boolean | string ->(x = 10 && x.toString()) : string ->x = 10 && x.toString() : string + ? ((x = 10) && x.toString()) // number | boolean | string +>((x = 10) && x.toString()) : string +>(x = 10) && x.toString() : string +>(x = 10) : number +>x = 10 : number >x : number | string | boolean ->10 && x.toString() : string >10 : number >x.toString() : string >x.toString : (radix?: number) => string ->x : number | string | boolean +>x : number >toString : (radix?: number) => string // do not change value - : (y = x && x.toString()))); // number | boolean | string ->(y = x && x.toString()) : string ->y = x && x.toString() : string + : ((y = x) && x.toString()))); // number | boolean | string +>((y = x) && x.toString()) : string +>(y = x) && x.toString() : string +>(y = x) : boolean +>y = x : boolean >y : number | boolean | string ->x && x.toString() : string ->x : number | string | boolean +>x : boolean >x.toString() : string ->x.toString : (radix?: number) => string ->x : number | string | boolean ->toString : (radix?: number) => string +>x.toString : () => string +>x : boolean +>toString : () => string } -function foo8(x: number | string) { ->foo8 : (x: number | string) => boolean | number ->x : number | string - // Mixing typeguard - // Assigning value to x in outer guard shouldn't stop narrowing in the inner expression - return typeof x === "string" ->typeof x === "string" || (x = 10) // change x - number| string || (typeof x === "number" ? x // number : x.length) : boolean | number ->typeof x === "string" || (x = 10) : boolean | number ->typeof x === "string" : boolean ->typeof x : string ->x : number | string ->"string" : string - - || (x = 10) // change x - number| string ->(x = 10) : number ->x = 10 : number ->x : number | string ->10 : number - - || (typeof x === "number" ->(typeof x === "number" ? x // number : x.length) : number ->typeof x === "number" ? x // number : x.length : number ->typeof x === "number" : boolean ->typeof x : string ->x : number | string ->"number" : string - - ? x // number ->x : number - - : x.length); // string ->x.length : number ->x : string ->length : number -} diff --git a/tests/baselines/reference/typeGuardsInWhileStatement.js b/tests/baselines/reference/typeGuardsInWhileStatement.js new file mode 100644 index 00000000000..ac2ceaaf590 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInWhileStatement.js @@ -0,0 +1,54 @@ +//// [typeGuardsInWhileStatement.ts] +let cond: boolean; +function a(x: string | number) { + while (typeof x === "string") { + x; // string + x = undefined; + } + x; // number +} +function b(x: string | number) { + while (typeof x === "string") { + if (cond) continue; + x; // string + x = undefined; + } + x; // number +} +function c(x: string | number) { + while (typeof x === "string") { + if (cond) break; + x; // string + x = undefined; + } + x; // string | number +} + + +//// [typeGuardsInWhileStatement.js] +var cond; +function a(x) { + while (typeof x === "string") { + x; // string + x = undefined; + } + x; // number +} +function b(x) { + while (typeof x === "string") { + if (cond) + continue; + x; // string + x = undefined; + } + x; // number +} +function c(x) { + while (typeof x === "string") { + if (cond) + break; + x; // string + x = undefined; + } + x; // string | number +} diff --git a/tests/baselines/reference/typeGuardsInWhileStatement.symbols b/tests/baselines/reference/typeGuardsInWhileStatement.symbols new file mode 100644 index 00000000000..b981943e216 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInWhileStatement.symbols @@ -0,0 +1,62 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardsInWhileStatement.ts === +let cond: boolean; +>cond : Symbol(cond, Decl(typeGuardsInWhileStatement.ts, 0, 3)) + +function a(x: string | number) { +>a : Symbol(a, Decl(typeGuardsInWhileStatement.ts, 0, 18)) +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 1, 11)) + + while (typeof x === "string") { +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 1, 11)) + + x; // string +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 1, 11)) + + x = undefined; +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 1, 11)) +>undefined : Symbol(undefined) + } + x; // number +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 1, 11)) +} +function b(x: string | number) { +>b : Symbol(b, Decl(typeGuardsInWhileStatement.ts, 7, 1)) +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 8, 11)) + + while (typeof x === "string") { +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 8, 11)) + + if (cond) continue; +>cond : Symbol(cond, Decl(typeGuardsInWhileStatement.ts, 0, 3)) + + x; // string +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 8, 11)) + + x = undefined; +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 8, 11)) +>undefined : Symbol(undefined) + } + x; // number +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 8, 11)) +} +function c(x: string | number) { +>c : Symbol(c, Decl(typeGuardsInWhileStatement.ts, 15, 1)) +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 16, 11)) + + while (typeof x === "string") { +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 16, 11)) + + if (cond) break; +>cond : Symbol(cond, Decl(typeGuardsInWhileStatement.ts, 0, 3)) + + x; // string +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 16, 11)) + + x = undefined; +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 16, 11)) +>undefined : Symbol(undefined) + } + x; // string | number +>x : Symbol(x, Decl(typeGuardsInWhileStatement.ts, 16, 11)) +} + diff --git a/tests/baselines/reference/typeGuardsInWhileStatement.types b/tests/baselines/reference/typeGuardsInWhileStatement.types new file mode 100644 index 00000000000..cde045cc621 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInWhileStatement.types @@ -0,0 +1,74 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardsInWhileStatement.ts === +let cond: boolean; +>cond : boolean + +function a(x: string | number) { +>a : (x: string | number) => void +>x : string | number + + while (typeof x === "string") { +>typeof x === "string" : boolean +>typeof x : string +>x : string | number +>"string" : string + + x; // string +>x : string + + x = undefined; +>x = undefined : undefined +>x : string | number +>undefined : undefined + } + x; // number +>x : number +} +function b(x: string | number) { +>b : (x: string | number) => void +>x : string | number + + while (typeof x === "string") { +>typeof x === "string" : boolean +>typeof x : string +>x : string | number +>"string" : string + + if (cond) continue; +>cond : boolean + + x; // string +>x : string + + x = undefined; +>x = undefined : undefined +>x : string | number +>undefined : undefined + } + x; // number +>x : number +} +function c(x: string | number) { +>c : (x: string | number) => void +>x : string | number + + while (typeof x === "string") { +>typeof x === "string" : boolean +>typeof x : string +>x : string | number +>"string" : string + + if (cond) break; +>cond : boolean + + x; // string +>x : string + + x = undefined; +>x = undefined : undefined +>x : string | number +>undefined : undefined + } + x; // string | number +>x : number | string +} + diff --git a/tests/baselines/reference/unionTypesAssignability.errors.txt b/tests/baselines/reference/unionTypesAssignability.errors.txt index cad61f41d1d..5be1ff3d246 100644 --- a/tests/baselines/reference/unionTypesAssignability.errors.txt +++ b/tests/baselines/reference/unionTypesAssignability.errors.txt @@ -24,9 +24,9 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTyp tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts(43,1): error TS2322: Type 'string' is not assignable to type 'number'. tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts(64,5): error TS2322: Type 'U' is not assignable to type 'T'. tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts(65,5): error TS2322: Type 'T' is not assignable to type 'U'. -tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts(69,5): error TS2322: Type 'T | U' is not assignable to type 'T'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts(70,5): error TS2322: Type 'T | U' is not assignable to type 'T'. Type 'U' is not assignable to type 'T'. -tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts(70,5): error TS2322: Type 'T | U' is not assignable to type 'U'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTypesAssignability.ts(71,5): error TS2322: Type 'T | U' is not assignable to type 'U'. Type 'T' is not assignable to type 'U'. @@ -142,6 +142,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/unionTyp var x : T | U; x = t; // ok x = u; // ok + x = undefined; t = x; // error U not assignable to T ~ !!! error TS2322: Type 'T | U' is not assignable to type 'T'. diff --git a/tests/baselines/reference/unionTypesAssignability.js b/tests/baselines/reference/unionTypesAssignability.js index e07901347a5..c7105608004 100644 --- a/tests/baselines/reference/unionTypesAssignability.js +++ b/tests/baselines/reference/unionTypesAssignability.js @@ -67,6 +67,7 @@ function foo(t: T, u: U) { var x : T | U; x = t; // ok x = u; // ok + x = undefined; t = x; // error U not assignable to T u = x; // error T not assignable to U } @@ -157,6 +158,7 @@ function foo(t, u) { var x; x = t; // ok x = u; // ok + x = undefined; t = x; // error U not assignable to T u = x; // error T not assignable to U } From 424074ba6bd1b9cf699cf6da15e95f5822272499 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Mar 2016 19:58:17 -0700 Subject: [PATCH 019/110] Use type {} for vacuous type guards / New getTypeWithFacts function --- src/compiler/checker.ts | 224 ++++++++++++++++++++++++++++------------ 1 file changed, 157 insertions(+), 67 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d8c62dd2da3..871b485809b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -122,7 +122,7 @@ namespace ts { const resolvingFlowType = createIntrinsicType(TypeFlags.Void, "__resolving__"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const emptyUnionType = emptyObjectType; + const emptyUnionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); emptyGenericType.instantiations = {}; @@ -194,27 +194,74 @@ namespace ts { const diagnostics = createDiagnosticCollection(); - const primitiveTypeInfo: Map<{ type: Type; flags: TypeFlags }> = { - "string": { - type: stringType, - flags: TypeFlags.StringLike - }, - "number": { - type: numberType, - flags: TypeFlags.NumberLike - }, - "boolean": { - type: booleanType, - flags: TypeFlags.Boolean - }, - "symbol": { - type: esSymbolType, - flags: TypeFlags.ESSymbol - }, - "undefined": { - type: undefinedType, - flags: TypeFlags.ContainsUndefinedOrNull - } + const enum TypeFacts { + None = 0, + TypeofEQString = 1 << 0, // typeof x === "string" + TypeofEQNumber = 1 << 1, // typeof x === "number" + TypeofEQBoolean = 1 << 2, // typeof x === "boolean" + TypeofEQSymbol = 1 << 3, // typeof x === "symbol" + TypeofEQObject = 1 << 4, // typeof x === "object" + TypeofEQFunction = 1 << 5, // typeof x === "function" + TypeofNEString = 1 << 6, // typeof x !== "string" + TypeofNENumber = 1 << 7, // typeof x !== "number" + TypeofNEBoolean = 1 << 8, // typeof x !== "boolean" + TypeofNESymbol = 1 << 9, // typeof x !== "symbol" + TypeofNEObject = 1 << 10, // typeof x !== "object" + TypeofNEFunction = 1 << 11, // typeof x !== "function" + EQUndefined = 1 << 12, // x === undefined + EQNull = 1 << 13, // x === null + EQUndefinedOrNull = 1 << 14, // x == undefined / x == null + NEUndefined = 1 << 15, // x !== undefined + NENull = 1 << 16, // x !== null + NEUndefinedOrNull = 1 << 17, // x != undefined / x != null + Truthy = 1 << 18, // x + Falsy = 1 << 19, // !x + All = (1 << 20) - 1, + // The following members encode facts about particular kinds of types for use in the getTypeFacts function. + // The presence of a particular fact means that the given test is true for some (and possibly all) values + // of that kind of type. + StringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, + StringFacts = StringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull, + NumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, + NumberFacts = NumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull, + BooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, + BooleanFacts = BooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull, + SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + ObjectStrictFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + FunctionStrictFacts = TypeofEQFunction | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | EQUndefined | EQUndefinedOrNull | NENull | Falsy, + NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | EQNull | EQUndefinedOrNull | NEUndefined | Falsy, + } + + const typeofEQFacts: Map = { + "string": TypeFacts.TypeofEQString, + "number": TypeFacts.TypeofEQNumber, + "boolean": TypeFacts.TypeofEQBoolean, + "symbol": TypeFacts.TypeofEQSymbol, + "undefined": TypeFacts.EQUndefined, + "object": TypeFacts.TypeofEQObject, + "function": TypeFacts.TypeofEQFunction + }; + + const typeofNEFacts: Map = { + "string": TypeFacts.TypeofNEString, + "number": TypeFacts.TypeofNENumber, + "boolean": TypeFacts.TypeofNEBoolean, + "symbol": TypeFacts.TypeofNESymbol, + "undefined": TypeFacts.NEUndefined, + "object": TypeFacts.TypeofNEObject, + "function": TypeFacts.TypeofNEFunction + }; + + const typeofTypesByName: Map = { + "string": stringType, + "number": numberType, + "boolean": booleanType, + "symbol": esSymbolType, + "undefined": undefinedType }; let jsxElementType: ObjectType; @@ -4823,7 +4870,7 @@ namespace ts { if (type.flags & TypeFlags.Undefined) typeSet.containsUndefined = true; if (type.flags & TypeFlags.Null) typeSet.containsNull = true; } - else if (!contains(typeSet, type)) { + else if (type !== emptyUnionType && !contains(typeSet, type)) { typeSet.push(type); } } @@ -4879,7 +4926,9 @@ namespace ts { removeSubtypes(typeSet); } if (typeSet.length === 0) { - return typeSet.containsNull ? nullType : undefinedType; + return typeSet.containsNull ? nullType : + typeSet.containsUndefined ? undefinedType : + emptyUnionType; } else if (typeSet.length === 1) { return typeSet[0]; @@ -5637,7 +5686,7 @@ namespace ts { return isIdenticalTo(source, target); } - if (isTypeAny(target)) return Ternary.True; + if (target.flags & TypeFlags.Any) return Ternary.True; if (source.flags & TypeFlags.Undefined) { if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void) || source === emptyArrayElementType) return Ternary.True; } @@ -6556,11 +6605,6 @@ namespace ts { return flags & TypeFlags.Nullable; } - function getNullableTypeOfKind(kind: TypeFlags) { - return kind & TypeFlags.Null ? kind & TypeFlags.Undefined ? - getUnionType([nullType, undefinedType]) : nullType : undefinedType; - } - function addNullableKind(type: Type, kind: TypeFlags): Type { if ((getNullableKind(type) & kind) !== kind) { const types = [type]; @@ -6576,7 +6620,10 @@ namespace ts { } function removeNullableKind(type: Type, kind: TypeFlags) { - if (type.flags & TypeFlags.Union && getNullableKind(type) & kind) { + if (!(getNullableKind(type) & kind)) { + return type; + } + if (type.flags & TypeFlags.Union) { let firstType: Type; let types: Type[]; for (const t of (type as UnionType).types) { @@ -6593,10 +6640,10 @@ namespace ts { } } if (firstType) { - type = types ? getUnionType(types) : firstType; + return types ? getUnionType(types) : firstType; } } - return type; + return emptyUnionType; } function getNonNullableType(type: Type): Type { @@ -7255,6 +7302,64 @@ namespace ts { return declaredType; } + function getTypeFacts(type: Type): TypeFacts { + const flags = type.flags; + if (flags & TypeFlags.StringLike) { + return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; + } + if (flags & TypeFlags.NumberLike) { + return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; + } + if (flags & TypeFlags.Boolean) { + return strictNullChecks ? TypeFacts.BooleanStrictFacts : TypeFacts.BooleanFacts; + } + if (flags & TypeFlags.ObjectType) { + const resolved = resolveStructuredTypeMembers(type); + return resolved.callSignatures.length || resolved.constructSignatures.length ? + strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : + strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; + } + if (flags & (TypeFlags.Void | TypeFlags.Undefined)) { + return TypeFacts.UndefinedFacts; + } + if (flags & TypeFlags.Null) { + return TypeFacts.NullFacts; + } + if (flags & TypeFlags.ESSymbol) { + return strictNullChecks ? TypeFacts.SymbolStrictFacts : TypeFacts.SymbolFacts; + } + if (flags & TypeFlags.TypeParameter) { + const constraint = getConstraintOfTypeParameter(type); + return constraint ? getTypeFacts(constraint) : TypeFacts.All; + } + if (flags & TypeFlags.Intersection) { + return reduceLeft((type).types, (flags, type) => flags |= getTypeFacts(type), TypeFacts.None); + } + return TypeFacts.All; + } + + function getTypeWithFacts(type: Type, include: TypeFacts) { + if (!(type.flags & TypeFlags.Union)) { + return getTypeFacts(type) & include ? type : emptyUnionType; + } + let firstType: Type; + let types: Type[]; + for (const t of (type as UnionType).types) { + if (getTypeFacts(t) & include) { + if (!firstType) { + firstType = t; + } + else { + if (!types) { + types = [firstType]; + } + types.push(t); + } + } + } + return firstType ? types ? getUnionType(types, /*noSubtypeReduction*/ true) : firstType : emptyUnionType; + } + function getNarrowedTypeOfReference(type: Type, reference: Node) { if (!(type.flags & TypeFlags.Narrowable) || !isNarrowableReference(reference)) { return type; @@ -7407,7 +7512,7 @@ namespace ts { } function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { - return strictNullChecks && assumeTrue && isMatchingReference(expr, reference) ? getNonNullableType(type) : type; + return isMatchingReference(expr, reference) ? getTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy) : type; } function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { @@ -7443,13 +7548,12 @@ namespace ts { return type; } const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken; - const exprNullableKind = doubleEquals ? TypeFlags.Nullable : - expr.right.kind === SyntaxKind.NullKeyword ? TypeFlags.Null : TypeFlags.Undefined; - if (assumeTrue) { - const nullableKind = getNullableKind(type) & exprNullableKind; - return nullableKind ? getNullableTypeOfKind(nullableKind) : type; - } - return removeNullableKind(type, exprNullableKind); + const facts = doubleEquals ? + assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull : + expr.right.kind === SyntaxKind.NullKeyword ? + assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : + assumeTrue ? TypeFacts.EQUndefined: TypeFacts.NEUndefined; + return getTypeWithFacts(type, facts); } function narrowTypeByTypeof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { @@ -7464,33 +7568,19 @@ namespace ts { expr.operatorToken.kind === SyntaxKind.ExclamationEqualsEqualsToken) { assumeTrue = !assumeTrue; } - const typeInfo = primitiveTypeInfo[right.text]; - // Don't narrow `undefined` - if (typeInfo && typeInfo.type === undefinedType) { - return type; - } - let flags: TypeFlags; - if (typeInfo) { - flags = typeInfo.flags; - } - else { - assumeTrue = !assumeTrue; - flags = TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.ESSymbol | TypeFlags.Boolean; - } - // At this point we can bail if it's not a union - if (!(type.flags & TypeFlags.Union)) { - // If we're on the true branch and the type is a subtype, we should return the primitive type - if (assumeTrue && typeInfo && isTypeSubtypeOf(typeInfo.type, type)) { - return typeInfo.type; + if (assumeTrue && !(type.flags & TypeFlags.Union)) { + // We narrow a non-union type to an exact primitive type if the non-union type + // is a supertype of that primtive type. For example, type 'any' can be narrowed + // to one of the primitive types. + const targetType = getProperty(typeofTypesByName, right.text); + if (targetType && isTypeSubtypeOf(targetType, type)) { + return targetType; } - // If the active non-union type would be removed from a union by this type guard, return an empty union - return filterUnion(type) ? type : emptyUnionType; - } - return getUnionType(filter((type as UnionType).types, filterUnion), /*noSubtypeReduction*/ true); - - function filterUnion(type: Type) { - return assumeTrue === !!(type.flags & flags); } + const facts = assumeTrue ? + getProperty(typeofEQFacts, right.text) || TypeFacts.TypeofEQObject : + getProperty(typeofNEFacts, right.text) || TypeFacts.TypeofNEObject; + return getTypeWithFacts(type, facts); } function narrowTypeByAnd(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { @@ -14243,7 +14333,7 @@ namespace ts { // Now that we've removed all the StringLike types, if no constituents remain, then the entire // arrayOrStringType was a string. - if (arrayType === emptyObjectType) { + if (arrayType === emptyUnionType) { return stringType; } } From c6f4de36071132081f05de5e32e79f9862418f83 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Mar 2016 19:58:43 -0700 Subject: [PATCH 020/110] Remove unnecessary cast --- src/harness/loggedIO.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/harness/loggedIO.ts b/src/harness/loggedIO.ts index 2c4d019d45b..2763aeab34c 100644 --- a/src/harness/loggedIO.ts +++ b/src/harness/loggedIO.ts @@ -149,7 +149,7 @@ namespace Playback { recordLog = createEmptyLog(); if (typeof underlying.args !== "function") { - recordLog.arguments = underlying.args; + recordLog.arguments = underlying.args; } }; From e53f390b3e0dfd6e3efd7f23f99a70e44a425a93 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Mar 2016 19:59:05 -0700 Subject: [PATCH 021/110] Fix some tests --- .../typeGuards/typeGuardOfFormTypeOfBoolean.ts | 10 ++++------ .../typeGuards/typeGuardOfFormTypeOfNumber.ts | 10 ++++------ .../typeGuards/typeGuardOfFormTypeOfOther.ts | 10 ++++------ .../typeGuards/typeGuardOfFormTypeOfString.ts | 10 ++++------ 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfBoolean.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfBoolean.ts index fb699ce8ce0..37651071b7f 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfBoolean.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfBoolean.ts @@ -41,12 +41,11 @@ else { c = boolOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum === "boolean") { - var z1: string | number = strOrNum; // string | number + let z1: {} = strOrNum; // {} } else { - var z2: string | number = strOrNum; // string | number + let z2: string | number = strOrNum; // string | number } @@ -78,10 +77,9 @@ else { bool = boolOrC; // boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum !== "boolean") { - var z1: string | number = strOrNum; // string | number + let z1: string | number = strOrNum; // string | number } else { - var z2: string | number = strOrNum; // string | number + let z2: {} = strOrNum; // {} } diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfNumber.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfNumber.ts index 2868b114077..b4cdf81660e 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfNumber.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfNumber.ts @@ -41,12 +41,11 @@ else { c = numOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool === "number") { - var y1: string | boolean = strOrBool; // string | boolean + let y1: {} = strOrBool; // {} } else { - var y2: string | boolean = strOrBool; // string | boolean + let y2: string | boolean = strOrBool; // string | boolean } // A type guard of the form typeof x !== s, where s is a string literal, @@ -77,10 +76,9 @@ else { num = numOrC; // number } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool !== "number") { - var y1: string | boolean = strOrBool; // string | boolean + let y1: string | boolean = strOrBool; // string | boolean } else { - var y2: string | boolean = strOrBool; // string | boolean + let y2: {} = strOrBool; // {} } diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfOther.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfOther.ts index ac3403d8151..44b064c3219 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfOther.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfOther.ts @@ -37,12 +37,11 @@ else { var r4: boolean = boolOrC; // boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool === "Object") { - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q1: {} = strOrNumOrBool; // {} } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q2: string | number | boolean = strOrNumOrBool; // string | number | boolean } // A type guard of the form typeof x !== s, where s is a string literal, @@ -67,10 +66,9 @@ else { c = boolOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool !== "Object") { - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q1: string | number | boolean = strOrNumOrBool; // string | number | boolean } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q2: {} = strOrNumOrBool; // {} } diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfString.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfString.ts index a356858e6c8..f742124708f 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfString.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfString.ts @@ -41,12 +41,11 @@ else { c = strOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool === "string") { - var x1: number | boolean = numOrBool; // number | boolean + let x1: {} = numOrBool; // {} } else { - var x2: number | boolean = numOrBool; // number | boolean + let x2: number | boolean = numOrBool; // number | boolean } // A type guard of the form typeof x !== s, where s is a string literal, @@ -77,10 +76,9 @@ else { str = strOrC; // string } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool !== "string") { - var x1: number | boolean = numOrBool; // number | boolean + let x1: number | boolean = numOrBool; // number | boolean } else { - var x2: number | boolean = numOrBool; // number | boolean + let x2: {} = numOrBool; // {} } From a38d86391002b7a9bb0ba4c666be3bae015f1cce Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Mar 2016 20:00:40 -0700 Subject: [PATCH 022/110] Accepting new baselines --- .../reference/typeGuardOfFormTypeOfBoolean.js | 16 ++++----- .../typeGuardOfFormTypeOfBoolean.symbols | 18 +++++----- .../typeGuardOfFormTypeOfBoolean.types | 24 ++++++------- .../reference/typeGuardOfFormTypeOfNumber.js | 16 ++++----- .../typeGuardOfFormTypeOfNumber.symbols | 22 ++++++------ .../typeGuardOfFormTypeOfNumber.types | 22 ++++++------ .../reference/typeGuardOfFormTypeOfOther.js | 16 ++++----- .../typeGuardOfFormTypeOfOther.symbols | 30 ++++++++-------- .../typeGuardOfFormTypeOfOther.types | 24 ++++++------- .../reference/typeGuardOfFormTypeOfString.js | 16 ++++----- .../typeGuardOfFormTypeOfString.symbols | 18 +++++----- .../typeGuardOfFormTypeOfString.types | 18 +++++----- .../typeGuardTautologicalConsistiency.types | 6 ++-- .../reference/typeGuardTypeOfUndefined.types | 34 +++++++++---------- 14 files changed, 124 insertions(+), 156 deletions(-) diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.js b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.js index e9e11275d0d..7d68b893373 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.js +++ b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.js @@ -42,12 +42,11 @@ else { c = boolOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum === "boolean") { - var z1: string | number = strOrNum; // string | number + let z1: {} = strOrNum; // {} } else { - var z2: string | number = strOrNum; // string | number + let z2: string | number = strOrNum; // string | number } @@ -79,12 +78,11 @@ else { bool = boolOrC; // boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum !== "boolean") { - var z1: string | number = strOrNum; // string | number + let z1: string | number = strOrNum; // string | number } else { - var z2: string | number = strOrNum; // string | number + let z2: {} = strOrNum; // {} } @@ -134,9 +132,8 @@ if (typeof boolOrC === "boolean") { else { c = boolOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum === "boolean") { - var z1 = strOrNum; // string | number + var z1 = strOrNum; // {} } else { var z2 = strOrNum; // string | number @@ -168,10 +165,9 @@ if (typeof boolOrC !== "boolean") { else { bool = boolOrC; // boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum !== "boolean") { var z1 = strOrNum; // string | number } else { - var z2 = strOrNum; // string | number + var z2 = strOrNum; // {} } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.symbols b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.symbols index d3879519228..dbef84c28c7 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.symbols +++ b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.symbols @@ -93,17 +93,16 @@ else { >boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfBoolean.ts, 11, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum === "boolean") { >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfBoolean.ts, 5, 3)) - var z1: string | number = strOrNum; // string | number ->z1 : Symbol(z1, Decl(typeGuardOfFormTypeOfBoolean.ts, 45, 7), Decl(typeGuardOfFormTypeOfBoolean.ts, 82, 7)) + let z1: {} = strOrNum; // {} +>z1 : Symbol(z1, Decl(typeGuardOfFormTypeOfBoolean.ts, 44, 7)) >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfBoolean.ts, 5, 3)) } else { - var z2: string | number = strOrNum; // string | number ->z2 : Symbol(z2, Decl(typeGuardOfFormTypeOfBoolean.ts, 48, 7), Decl(typeGuardOfFormTypeOfBoolean.ts, 85, 7)) + let z2: string | number = strOrNum; // string | number +>z2 : Symbol(z2, Decl(typeGuardOfFormTypeOfBoolean.ts, 47, 7)) >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfBoolean.ts, 5, 3)) } @@ -160,17 +159,16 @@ else { >boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfBoolean.ts, 11, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum !== "boolean") { >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfBoolean.ts, 5, 3)) - var z1: string | number = strOrNum; // string | number ->z1 : Symbol(z1, Decl(typeGuardOfFormTypeOfBoolean.ts, 45, 7), Decl(typeGuardOfFormTypeOfBoolean.ts, 82, 7)) + let z1: string | number = strOrNum; // string | number +>z1 : Symbol(z1, Decl(typeGuardOfFormTypeOfBoolean.ts, 80, 7)) >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfBoolean.ts, 5, 3)) } else { - var z2: string | number = strOrNum; // string | number ->z2 : Symbol(z2, Decl(typeGuardOfFormTypeOfBoolean.ts, 48, 7), Decl(typeGuardOfFormTypeOfBoolean.ts, 85, 7)) + let z2: {} = strOrNum; // {} +>z2 : Symbol(z2, Decl(typeGuardOfFormTypeOfBoolean.ts, 83, 7)) >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfBoolean.ts, 5, 3)) } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types index 9d9f28548be..a5dcc9207cd 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types @@ -113,19 +113,18 @@ else { >boolOrC : C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum === "boolean") { >typeof strOrNum === "boolean" : boolean >typeof strOrNum : string >strOrNum : string | number >"boolean" : string - var z1: string | number = strOrNum; // string | number ->z1 : string | number ->strOrNum : string | number + let z1: {} = strOrNum; // {} +>z1 : {} +>strOrNum : {} } else { - var z2: string | number = strOrNum; // string | number + let z2: string | number = strOrNum; // string | number >z2 : string | number >strOrNum : string | number } @@ -137,7 +136,7 @@ else { if (typeof strOrBool !== "boolean") { >typeof strOrBool !== "boolean" : boolean >typeof strOrBool : string ->strOrBool : string | boolean +>strOrBool : boolean | string >"boolean" : string str = strOrBool; // string @@ -154,7 +153,7 @@ else { if (typeof numOrBool !== "boolean") { >typeof numOrBool !== "boolean" : boolean >typeof numOrBool : string ->numOrBool : number | boolean +>numOrBool : boolean | number >"boolean" : string num = numOrBool; // number @@ -171,7 +170,7 @@ else { if (typeof strOrNumOrBool !== "boolean") { >typeof strOrNumOrBool !== "boolean" : boolean >typeof strOrNumOrBool : string ->strOrNumOrBool : string | number | boolean +>strOrNumOrBool : boolean | string | number >"boolean" : string strOrNum = strOrNumOrBool; // string | number @@ -203,20 +202,19 @@ else { >boolOrC : boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNum !== "boolean") { >typeof strOrNum !== "boolean" : boolean >typeof strOrNum : string >strOrNum : string | number >"boolean" : string - var z1: string | number = strOrNum; // string | number + let z1: string | number = strOrNum; // string | number >z1 : string | number >strOrNum : string | number } else { - var z2: string | number = strOrNum; // string | number ->z2 : string | number ->strOrNum : string | number + let z2: {} = strOrNum; // {} +>z2 : {} +>strOrNum : {} } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.js b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.js index 66fcff0c387..3bea6e87d2b 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.js +++ b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.js @@ -42,12 +42,11 @@ else { c = numOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool === "number") { - var y1: string | boolean = strOrBool; // string | boolean + let y1: {} = strOrBool; // {} } else { - var y2: string | boolean = strOrBool; // string | boolean + let y2: string | boolean = strOrBool; // string | boolean } // A type guard of the form typeof x !== s, where s is a string literal, @@ -78,12 +77,11 @@ else { num = numOrC; // number } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool !== "number") { - var y1: string | boolean = strOrBool; // string | boolean + let y1: string | boolean = strOrBool; // string | boolean } else { - var y2: string | boolean = strOrBool; // string | boolean + let y2: {} = strOrBool; // {} } @@ -133,9 +131,8 @@ if (typeof numOrC === "number") { else { c = numOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool === "number") { - var y1 = strOrBool; // string | boolean + var y1 = strOrBool; // {} } else { var y2 = strOrBool; // string | boolean @@ -167,10 +164,9 @@ if (typeof numOrC !== "number") { else { num = numOrC; // number } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool !== "number") { var y1 = strOrBool; // string | boolean } else { - var y2 = strOrBool; // string | boolean + var y2 = strOrBool; // {} } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.symbols b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.symbols index 2fd48389ae8..f38c348131e 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.symbols +++ b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.symbols @@ -65,7 +65,7 @@ if (typeof numOrBool === "number") { } else { var x: number | boolean = numOrBool; // number | boolean ->x : Symbol(x, Decl(typeGuardOfFormTypeOfNumber.ts, 28, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 61, 7)) +>x : Symbol(x, Decl(typeGuardOfFormTypeOfNumber.ts, 28, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 60, 7)) >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 7, 3)) } if (typeof strOrNumOrBool === "number") { @@ -93,17 +93,16 @@ else { >numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfNumber.ts, 10, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool === "number") { >strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 6, 3)) - var y1: string | boolean = strOrBool; // string | boolean ->y1 : Symbol(y1, Decl(typeGuardOfFormTypeOfNumber.ts, 45, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 81, 7)) + let y1: {} = strOrBool; // {} +>y1 : Symbol(y1, Decl(typeGuardOfFormTypeOfNumber.ts, 44, 7)) >strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 6, 3)) } else { - var y2: string | boolean = strOrBool; // string | boolean ->y2 : Symbol(y2, Decl(typeGuardOfFormTypeOfNumber.ts, 48, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 84, 7)) + let y2: string | boolean = strOrBool; // string | boolean +>y2 : Symbol(y2, Decl(typeGuardOfFormTypeOfNumber.ts, 47, 7)) >strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 6, 3)) } @@ -126,7 +125,7 @@ if (typeof numOrBool !== "number") { >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 7, 3)) var x: number | boolean = numOrBool; // number | boolean ->x : Symbol(x, Decl(typeGuardOfFormTypeOfNumber.ts, 28, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 61, 7)) +>x : Symbol(x, Decl(typeGuardOfFormTypeOfNumber.ts, 28, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 60, 7)) >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 7, 3)) } else { @@ -159,17 +158,16 @@ else { >numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfNumber.ts, 10, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool !== "number") { >strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 6, 3)) - var y1: string | boolean = strOrBool; // string | boolean ->y1 : Symbol(y1, Decl(typeGuardOfFormTypeOfNumber.ts, 45, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 81, 7)) + let y1: string | boolean = strOrBool; // string | boolean +>y1 : Symbol(y1, Decl(typeGuardOfFormTypeOfNumber.ts, 79, 7)) >strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 6, 3)) } else { - var y2: string | boolean = strOrBool; // string | boolean ->y2 : Symbol(y2, Decl(typeGuardOfFormTypeOfNumber.ts, 48, 7), Decl(typeGuardOfFormTypeOfNumber.ts, 84, 7)) + let y2: {} = strOrBool; // {} +>y2 : Symbol(y2, Decl(typeGuardOfFormTypeOfNumber.ts, 82, 7)) >strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfNumber.ts, 6, 3)) } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types index d3caef24efd..99f927b7137 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types @@ -112,19 +112,18 @@ else { >numOrC : C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool === "number") { >typeof strOrBool === "number" : boolean >typeof strOrBool : string >strOrBool : string | boolean >"number" : string - var y1: string | boolean = strOrBool; // string | boolean ->y1 : string | boolean ->strOrBool : string | boolean + let y1: {} = strOrBool; // {} +>y1 : {} +>strOrBool : {} } else { - var y2: string | boolean = strOrBool; // string | boolean + let y2: string | boolean = strOrBool; // string | boolean >y2 : string | boolean >strOrBool : string | boolean } @@ -135,7 +134,7 @@ else { if (typeof strOrNum !== "number") { >typeof strOrNum !== "number" : boolean >typeof strOrNum : string ->strOrNum : string | number +>strOrNum : number | string >"number" : string str === strOrNum; // string @@ -168,7 +167,7 @@ else { if (typeof strOrNumOrBool !== "number") { >typeof strOrNumOrBool !== "number" : boolean >typeof strOrNumOrBool : string ->strOrNumOrBool : string | number | boolean +>strOrNumOrBool : number | string | boolean >"number" : string strOrBool = strOrNumOrBool; // string | boolean @@ -200,20 +199,19 @@ else { >numOrC : number } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrBool !== "number") { >typeof strOrBool !== "number" : boolean >typeof strOrBool : string >strOrBool : string | boolean >"number" : string - var y1: string | boolean = strOrBool; // string | boolean + let y1: string | boolean = strOrBool; // string | boolean >y1 : string | boolean >strOrBool : string | boolean } else { - var y2: string | boolean = strOrBool; // string | boolean ->y2 : string | boolean ->strOrBool : string | boolean + let y2: {} = strOrBool; // {} +>y2 : {} +>strOrBool : {} } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfOther.js b/tests/baselines/reference/typeGuardOfFormTypeOfOther.js index b1e6ca26566..ee0b6f66332 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfOther.js +++ b/tests/baselines/reference/typeGuardOfFormTypeOfOther.js @@ -38,12 +38,11 @@ else { var r4: boolean = boolOrC; // boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool === "Object") { - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q1: {} = strOrNumOrBool; // {} } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q2: string | number | boolean = strOrNumOrBool; // string | number | boolean } // A type guard of the form typeof x !== s, where s is a string literal, @@ -68,12 +67,11 @@ else { c = boolOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool !== "Object") { - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q1: string | number | boolean = strOrNumOrBool; // string | number | boolean } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q2: {} = strOrNumOrBool; // {} } @@ -118,9 +116,8 @@ if (typeof boolOrC === "Object") { else { var r4 = boolOrC; // boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool === "Object") { - var q1 = strOrNumOrBool; // string | number | boolean + var q1 = strOrNumOrBool; // {} } else { var q2 = strOrNumOrBool; // string | number | boolean @@ -146,10 +143,9 @@ if (typeof boolOrC !== "Object") { else { c = boolOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool !== "Object") { var q1 = strOrNumOrBool; // string | number | boolean } else { - var q2 = strOrNumOrBool; // string | number | boolean + var q2 = strOrNumOrBool; // {} } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfOther.symbols b/tests/baselines/reference/typeGuardOfFormTypeOfOther.symbols index ba759871a9b..a8760feda45 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfOther.symbols +++ b/tests/baselines/reference/typeGuardOfFormTypeOfOther.symbols @@ -57,7 +57,7 @@ if (typeof strOrC === "Object") { } else { var r2: string = strOrC; // string ->r2 : Symbol(r2, Decl(typeGuardOfFormTypeOfOther.ts, 24, 7), Decl(typeGuardOfFormTypeOfOther.ts, 51, 7)) +>r2 : Symbol(r2, Decl(typeGuardOfFormTypeOfOther.ts, 24, 7), Decl(typeGuardOfFormTypeOfOther.ts, 50, 7)) >strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfOther.ts, 9, 3)) } if (typeof numOrC === "Object") { @@ -69,7 +69,7 @@ if (typeof numOrC === "Object") { } else { var r3: number = numOrC; // number ->r3 : Symbol(r3, Decl(typeGuardOfFormTypeOfOther.ts, 30, 7), Decl(typeGuardOfFormTypeOfOther.ts, 57, 7)) +>r3 : Symbol(r3, Decl(typeGuardOfFormTypeOfOther.ts, 30, 7), Decl(typeGuardOfFormTypeOfOther.ts, 56, 7)) >numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfOther.ts, 10, 3)) } if (typeof boolOrC === "Object") { @@ -81,21 +81,20 @@ if (typeof boolOrC === "Object") { } else { var r4: boolean = boolOrC; // boolean ->r4 : Symbol(r4, Decl(typeGuardOfFormTypeOfOther.ts, 36, 7), Decl(typeGuardOfFormTypeOfOther.ts, 63, 7)) +>r4 : Symbol(r4, Decl(typeGuardOfFormTypeOfOther.ts, 36, 7), Decl(typeGuardOfFormTypeOfOther.ts, 62, 7)) >boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool === "Object") { >strOrNumOrBool : Symbol(strOrNumOrBool, Decl(typeGuardOfFormTypeOfOther.ts, 8, 3)) - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean ->q1 : Symbol(q1, Decl(typeGuardOfFormTypeOfOther.ts, 41, 7), Decl(typeGuardOfFormTypeOfOther.ts, 71, 7)) + let q1: {} = strOrNumOrBool; // {} +>q1 : Symbol(q1, Decl(typeGuardOfFormTypeOfOther.ts, 40, 7)) >strOrNumOrBool : Symbol(strOrNumOrBool, Decl(typeGuardOfFormTypeOfOther.ts, 8, 3)) } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean ->q2 : Symbol(q2, Decl(typeGuardOfFormTypeOfOther.ts, 44, 7), Decl(typeGuardOfFormTypeOfOther.ts, 74, 7)) + let q2: string | number | boolean = strOrNumOrBool; // string | number | boolean +>q2 : Symbol(q2, Decl(typeGuardOfFormTypeOfOther.ts, 43, 7)) >strOrNumOrBool : Symbol(strOrNumOrBool, Decl(typeGuardOfFormTypeOfOther.ts, 8, 3)) } @@ -106,7 +105,7 @@ if (typeof strOrC !== "Object") { >strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfOther.ts, 9, 3)) var r2: string = strOrC; // string ->r2 : Symbol(r2, Decl(typeGuardOfFormTypeOfOther.ts, 24, 7), Decl(typeGuardOfFormTypeOfOther.ts, 51, 7)) +>r2 : Symbol(r2, Decl(typeGuardOfFormTypeOfOther.ts, 24, 7), Decl(typeGuardOfFormTypeOfOther.ts, 50, 7)) >strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfOther.ts, 9, 3)) } else { @@ -118,7 +117,7 @@ if (typeof numOrC !== "Object") { >numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfOther.ts, 10, 3)) var r3: number = numOrC; // number ->r3 : Symbol(r3, Decl(typeGuardOfFormTypeOfOther.ts, 30, 7), Decl(typeGuardOfFormTypeOfOther.ts, 57, 7)) +>r3 : Symbol(r3, Decl(typeGuardOfFormTypeOfOther.ts, 30, 7), Decl(typeGuardOfFormTypeOfOther.ts, 56, 7)) >numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfOther.ts, 10, 3)) } else { @@ -130,7 +129,7 @@ if (typeof boolOrC !== "Object") { >boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3)) var r4: boolean = boolOrC; // boolean ->r4 : Symbol(r4, Decl(typeGuardOfFormTypeOfOther.ts, 36, 7), Decl(typeGuardOfFormTypeOfOther.ts, 63, 7)) +>r4 : Symbol(r4, Decl(typeGuardOfFormTypeOfOther.ts, 36, 7), Decl(typeGuardOfFormTypeOfOther.ts, 62, 7)) >boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3)) } else { @@ -139,17 +138,16 @@ else { >boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool !== "Object") { >strOrNumOrBool : Symbol(strOrNumOrBool, Decl(typeGuardOfFormTypeOfOther.ts, 8, 3)) - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean ->q1 : Symbol(q1, Decl(typeGuardOfFormTypeOfOther.ts, 41, 7), Decl(typeGuardOfFormTypeOfOther.ts, 71, 7)) + let q1: string | number | boolean = strOrNumOrBool; // string | number | boolean +>q1 : Symbol(q1, Decl(typeGuardOfFormTypeOfOther.ts, 69, 7)) >strOrNumOrBool : Symbol(strOrNumOrBool, Decl(typeGuardOfFormTypeOfOther.ts, 8, 3)) } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean ->q2 : Symbol(q2, Decl(typeGuardOfFormTypeOfOther.ts, 44, 7), Decl(typeGuardOfFormTypeOfOther.ts, 74, 7)) + let q2: {} = strOrNumOrBool; // {} +>q2 : Symbol(q2, Decl(typeGuardOfFormTypeOfOther.ts, 72, 7)) >strOrNumOrBool : Symbol(strOrNumOrBool, Decl(typeGuardOfFormTypeOfOther.ts, 8, 3)) } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfOther.types b/tests/baselines/reference/typeGuardOfFormTypeOfOther.types index 5cec3567194..aba8e429b8c 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfOther.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfOther.types @@ -97,19 +97,18 @@ else { >boolOrC : boolean } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool === "Object") { >typeof strOrNumOrBool === "Object" : boolean >typeof strOrNumOrBool : string >strOrNumOrBool : string | number | boolean >"Object" : string - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean ->q1 : string | number | boolean ->strOrNumOrBool : string | number | boolean + let q1: {} = strOrNumOrBool; // {} +>q1 : {} +>strOrNumOrBool : {} } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q2: string | number | boolean = strOrNumOrBool; // string | number | boolean >q2 : string | number | boolean >strOrNumOrBool : string | number | boolean } @@ -120,7 +119,7 @@ else { if (typeof strOrC !== "Object") { >typeof strOrC !== "Object" : boolean >typeof strOrC : string ->strOrC : string | C +>strOrC : C | string >"Object" : string var r2: string = strOrC; // string @@ -136,7 +135,7 @@ else { if (typeof numOrC !== "Object") { >typeof numOrC !== "Object" : boolean >typeof numOrC : string ->numOrC : number | C +>numOrC : C | number >"Object" : string var r3: number = numOrC; // number @@ -152,7 +151,7 @@ else { if (typeof boolOrC !== "Object") { >typeof boolOrC !== "Object" : boolean >typeof boolOrC : string ->boolOrC : boolean | C +>boolOrC : C | boolean >"Object" : string var r4: boolean = boolOrC; // boolean @@ -166,20 +165,19 @@ else { >boolOrC : C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof strOrNumOrBool !== "Object") { >typeof strOrNumOrBool !== "Object" : boolean >typeof strOrNumOrBool : string >strOrNumOrBool : string | number | boolean >"Object" : string - var q1: string | number | boolean = strOrNumOrBool; // string | number | boolean + let q1: string | number | boolean = strOrNumOrBool; // string | number | boolean >q1 : string | number | boolean >strOrNumOrBool : string | number | boolean } else { - var q2: string | number | boolean = strOrNumOrBool; // string | number | boolean ->q2 : string | number | boolean ->strOrNumOrBool : string | number | boolean + let q2: {} = strOrNumOrBool; // {} +>q2 : {} +>strOrNumOrBool : {} } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfString.js b/tests/baselines/reference/typeGuardOfFormTypeOfString.js index 5626396f73d..d79f73a87c5 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfString.js +++ b/tests/baselines/reference/typeGuardOfFormTypeOfString.js @@ -42,12 +42,11 @@ else { c = strOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool === "string") { - var x1: number | boolean = numOrBool; // number | boolean + let x1: {} = numOrBool; // {} } else { - var x2: number | boolean = numOrBool; // number | boolean + let x2: number | boolean = numOrBool; // number | boolean } // A type guard of the form typeof x !== s, where s is a string literal, @@ -78,12 +77,11 @@ else { str = strOrC; // string } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool !== "string") { - var x1: number | boolean = numOrBool; // number | boolean + let x1: number | boolean = numOrBool; // number | boolean } else { - var x2: number | boolean = numOrBool; // number | boolean + let x2: {} = numOrBool; // {} } @@ -133,9 +131,8 @@ if (typeof strOrC === "string") { else { c = strOrC; // C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool === "string") { - var x1 = numOrBool; // number | boolean + var x1 = numOrBool; // {} } else { var x2 = numOrBool; // number | boolean @@ -167,10 +164,9 @@ if (typeof strOrC !== "string") { else { str = strOrC; // string } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool !== "string") { var x1 = numOrBool; // number | boolean } else { - var x2 = numOrBool; // number | boolean + var x2 = numOrBool; // {} } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfString.symbols b/tests/baselines/reference/typeGuardOfFormTypeOfString.symbols index d3209189f83..4a77ecb1ffb 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfString.symbols +++ b/tests/baselines/reference/typeGuardOfFormTypeOfString.symbols @@ -93,17 +93,16 @@ else { >strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfString.ts, 9, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool === "string") { >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfString.ts, 7, 3)) - var x1: number | boolean = numOrBool; // number | boolean ->x1 : Symbol(x1, Decl(typeGuardOfFormTypeOfString.ts, 45, 7), Decl(typeGuardOfFormTypeOfString.ts, 81, 7)) + let x1: {} = numOrBool; // {} +>x1 : Symbol(x1, Decl(typeGuardOfFormTypeOfString.ts, 44, 7)) >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfString.ts, 7, 3)) } else { - var x2: number | boolean = numOrBool; // number | boolean ->x2 : Symbol(x2, Decl(typeGuardOfFormTypeOfString.ts, 48, 7), Decl(typeGuardOfFormTypeOfString.ts, 84, 7)) + let x2: number | boolean = numOrBool; // number | boolean +>x2 : Symbol(x2, Decl(typeGuardOfFormTypeOfString.ts, 47, 7)) >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfString.ts, 7, 3)) } @@ -159,17 +158,16 @@ else { >strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfString.ts, 9, 3)) } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool !== "string") { >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfString.ts, 7, 3)) - var x1: number | boolean = numOrBool; // number | boolean ->x1 : Symbol(x1, Decl(typeGuardOfFormTypeOfString.ts, 45, 7), Decl(typeGuardOfFormTypeOfString.ts, 81, 7)) + let x1: number | boolean = numOrBool; // number | boolean +>x1 : Symbol(x1, Decl(typeGuardOfFormTypeOfString.ts, 79, 7)) >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfString.ts, 7, 3)) } else { - var x2: number | boolean = numOrBool; // number | boolean ->x2 : Symbol(x2, Decl(typeGuardOfFormTypeOfString.ts, 48, 7), Decl(typeGuardOfFormTypeOfString.ts, 84, 7)) + let x2: {} = numOrBool; // {} +>x2 : Symbol(x2, Decl(typeGuardOfFormTypeOfString.ts, 82, 7)) >numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfString.ts, 7, 3)) } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfString.types b/tests/baselines/reference/typeGuardOfFormTypeOfString.types index d6a382261ac..c77f9f3207a 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfString.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfString.types @@ -113,19 +113,18 @@ else { >strOrC : C } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool === "string") { >typeof numOrBool === "string" : boolean >typeof numOrBool : string >numOrBool : number | boolean >"string" : string - var x1: number | boolean = numOrBool; // number | boolean ->x1 : number | boolean ->numOrBool : number | boolean + let x1: {} = numOrBool; // {} +>x1 : {} +>numOrBool : {} } else { - var x2: number | boolean = numOrBool; // number | boolean + let x2: number | boolean = numOrBool; // number | boolean >x2 : number | boolean >numOrBool : number | boolean } @@ -202,20 +201,19 @@ else { >strOrC : string } -// Narrowing occurs only if target type is a subtype of variable type if (typeof numOrBool !== "string") { >typeof numOrBool !== "string" : boolean >typeof numOrBool : string >numOrBool : number | boolean >"string" : string - var x1: number | boolean = numOrBool; // number | boolean + let x1: number | boolean = numOrBool; // number | boolean >x1 : number | boolean >numOrBool : number | boolean } else { - var x2: number | boolean = numOrBool; // number | boolean ->x2 : number | boolean ->numOrBool : number | boolean + let x2: {} = numOrBool; // {} +>x2 : {} +>numOrBool : {} } diff --git a/tests/baselines/reference/typeGuardTautologicalConsistiency.types b/tests/baselines/reference/typeGuardTautologicalConsistiency.types index d758dcde22b..100e528f616 100644 --- a/tests/baselines/reference/typeGuardTautologicalConsistiency.types +++ b/tests/baselines/reference/typeGuardTautologicalConsistiency.types @@ -15,7 +15,7 @@ if (typeof stringOrNumber === "number") { >"number" : string stringOrNumber; ->stringOrNumber : string | number +>stringOrNumber : {} } } @@ -23,7 +23,7 @@ if (typeof stringOrNumber === "number" && typeof stringOrNumber !== "number") { >typeof stringOrNumber === "number" && typeof stringOrNumber !== "number" : boolean >typeof stringOrNumber === "number" : boolean >typeof stringOrNumber : string ->stringOrNumber : string | number +>stringOrNumber : number | string >"number" : string >typeof stringOrNumber !== "number" : boolean >typeof stringOrNumber : string @@ -31,6 +31,6 @@ if (typeof stringOrNumber === "number" && typeof stringOrNumber !== "number") { >"number" : string stringOrNumber; ->stringOrNumber : string | number +>stringOrNumber : {} } diff --git a/tests/baselines/reference/typeGuardTypeOfUndefined.types b/tests/baselines/reference/typeGuardTypeOfUndefined.types index 6cf57e1a1dd..7073d9aeacb 100644 --- a/tests/baselines/reference/typeGuardTypeOfUndefined.types +++ b/tests/baselines/reference/typeGuardTypeOfUndefined.types @@ -26,7 +26,7 @@ function test1(a: any) { } else { a; ->a : any +>a : undefined } } @@ -43,15 +43,15 @@ function test2(a: any) { if (typeof a === "boolean") { >typeof a === "boolean" : boolean >typeof a : string ->a : any +>a : undefined >"boolean" : string a; ->a : boolean +>a : {} } else { a; ->a : any +>a : undefined } } else { @@ -76,7 +76,7 @@ function test3(a: any) { >"boolean" : string a; ->a : any +>a : boolean } else { a; @@ -121,7 +121,7 @@ function test5(a: boolean | void) { if (typeof a === "boolean") { >typeof a === "boolean" : boolean >typeof a : string ->a : boolean | void +>a : boolean >"boolean" : string a; @@ -129,7 +129,7 @@ function test5(a: boolean | void) { } else { a; ->a : void +>a : {} } } else { @@ -164,7 +164,7 @@ function test6(a: boolean | void) { } else { a; ->a : boolean | void +>a : boolean } } @@ -180,7 +180,7 @@ function test7(a: boolean | void) { >"undefined" : string >typeof a === "boolean" : boolean >typeof a : string ->a : boolean | void +>a : boolean >"boolean" : string a; @@ -188,7 +188,7 @@ function test7(a: boolean | void) { } else { a; ->a : void +>a : {} } } @@ -204,7 +204,7 @@ function test8(a: boolean | void) { >"undefined" : string >typeof a === "boolean" : boolean >typeof a : string ->a : boolean | void +>a : boolean >"boolean" : string a; @@ -337,7 +337,7 @@ function test13(a: boolean | number | void) { if (typeof a === "boolean") { >typeof a === "boolean" : boolean >typeof a : string ->a : boolean | number | void +>a : boolean | number >"boolean" : string a; @@ -345,7 +345,7 @@ function test13(a: boolean | number | void) { } else { a; ->a : number | void +>a : number } } else { @@ -380,7 +380,7 @@ function test14(a: boolean | number | void) { } else { a; ->a : boolean | number | void +>a : boolean | number } } @@ -396,7 +396,7 @@ function test15(a: boolean | number | void) { >"undefined" : string >typeof a === "boolean" : boolean >typeof a : string ->a : boolean | number | void +>a : boolean | number >"boolean" : string a; @@ -404,7 +404,7 @@ function test15(a: boolean | number | void) { } else { a; ->a : number | void +>a : number } } @@ -420,7 +420,7 @@ function test16(a: boolean | number | void) { >"undefined" : string >typeof a === "boolean" : boolean >typeof a : string ->a : boolean | number | void +>a : boolean | number >"boolean" : string a; From 3d0fa31a9d3f10896707915966ab7cd2aed33787 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Mar 2016 20:17:20 -0700 Subject: [PATCH 023/110] Delete removeNullableKind, use getTypeWithFacts instead --- src/compiler/checker.ts | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 871b485809b..1e05702d978 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2757,7 +2757,7 @@ namespace ts { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. if (strictNullChecks && declaration.initializer && !(getNullableKind(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) { - type = removeNullableKind(type, TypeFlags.Undefined); + type = getTypeWithFacts(type, TypeFacts.NEUndefined); } return type; } @@ -6619,35 +6619,8 @@ namespace ts { return type; } - function removeNullableKind(type: Type, kind: TypeFlags) { - if (!(getNullableKind(type) & kind)) { - return type; - } - if (type.flags & TypeFlags.Union) { - let firstType: Type; - let types: Type[]; - for (const t of (type as UnionType).types) { - if (!(t.flags & kind)) { - if (!firstType) { - firstType = t; - } - else { - if (!types) { - types = [firstType]; - } - types.push(t); - } - } - } - if (firstType) { - return types ? getUnionType(types) : firstType; - } - } - return emptyUnionType; - } - function getNonNullableType(type: Type): Type { - return strictNullChecks ? removeNullableKind(type, TypeFlags.Nullable) : type; + return strictNullChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } /** From ce81ba51566a328f6ee7c9f41f570675bea7ca3f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 31 Mar 2016 10:07:28 -0700 Subject: [PATCH 024/110] Support unknown types (host object names) in typeof type guards --- src/compiler/checker.ts | 64 +++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1e05702d978..da6548f8c69 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -196,44 +196,46 @@ namespace ts { const enum TypeFacts { None = 0, - TypeofEQString = 1 << 0, // typeof x === "string" - TypeofEQNumber = 1 << 1, // typeof x === "number" - TypeofEQBoolean = 1 << 2, // typeof x === "boolean" - TypeofEQSymbol = 1 << 3, // typeof x === "symbol" - TypeofEQObject = 1 << 4, // typeof x === "object" - TypeofEQFunction = 1 << 5, // typeof x === "function" - TypeofNEString = 1 << 6, // typeof x !== "string" - TypeofNENumber = 1 << 7, // typeof x !== "number" - TypeofNEBoolean = 1 << 8, // typeof x !== "boolean" - TypeofNESymbol = 1 << 9, // typeof x !== "symbol" - TypeofNEObject = 1 << 10, // typeof x !== "object" - TypeofNEFunction = 1 << 11, // typeof x !== "function" - EQUndefined = 1 << 12, // x === undefined - EQNull = 1 << 13, // x === null - EQUndefinedOrNull = 1 << 14, // x == undefined / x == null - NEUndefined = 1 << 15, // x !== undefined - NENull = 1 << 16, // x !== null - NEUndefinedOrNull = 1 << 17, // x != undefined / x != null - Truthy = 1 << 18, // x - Falsy = 1 << 19, // !x - All = (1 << 20) - 1, + TypeofEQString = 1 << 0, // typeof x === "string" + TypeofEQNumber = 1 << 1, // typeof x === "number" + TypeofEQBoolean = 1 << 2, // typeof x === "boolean" + TypeofEQSymbol = 1 << 3, // typeof x === "symbol" + TypeofEQObject = 1 << 4, // typeof x === "object" + TypeofEQFunction = 1 << 5, // typeof x === "function" + TypeofEQHostObject = 1 << 6, // typeof x === "xxx" + TypeofNEString = 1 << 7, // typeof x !== "string" + TypeofNENumber = 1 << 8, // typeof x !== "number" + TypeofNEBoolean = 1 << 9, // typeof x !== "boolean" + TypeofNESymbol = 1 << 10, // typeof x !== "symbol" + TypeofNEObject = 1 << 11, // typeof x !== "object" + TypeofNEFunction = 1 << 12, // typeof x !== "function" + TypeofNEHostObject = 1 << 13, // typeof x !== "xxx" + EQUndefined = 1 << 14, // x === undefined + EQNull = 1 << 15, // x === null + EQUndefinedOrNull = 1 << 16, // x == undefined / x == null + NEUndefined = 1 << 17, // x !== undefined + NENull = 1 << 18, // x !== null + NEUndefinedOrNull = 1 << 19, // x != undefined / x != null + Truthy = 1 << 20, // x + Falsy = 1 << 21, // !x + All = (1 << 22) - 1, // The following members encode facts about particular kinds of types for use in the getTypeFacts function. // The presence of a particular fact means that the given test is true for some (and possibly all) values // of that kind of type. - StringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, + StringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, StringFacts = StringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull, - NumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, + NumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, NumberFacts = NumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull, - BooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, + BooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Falsy, BooleanFacts = BooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull, - SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - ObjectStrictFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - FunctionStrictFacts = TypeofEQFunction | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | EQUndefined | EQUndefinedOrNull | NENull | Falsy, - NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | EQNull | EQUndefinedOrNull | NEUndefined | Falsy, + UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, + NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy, } const typeofEQFacts: Map = { @@ -7551,8 +7553,8 @@ namespace ts { } } const facts = assumeTrue ? - getProperty(typeofEQFacts, right.text) || TypeFacts.TypeofEQObject : - getProperty(typeofNEFacts, right.text) || TypeFacts.TypeofNEObject; + getProperty(typeofEQFacts, right.text) || TypeFacts.TypeofEQHostObject : + getProperty(typeofNEFacts, right.text) || TypeFacts.TypeofNEHostObject; return getTypeWithFacts(type, facts); } From 354fd10a2e12e49407615648579c8c00ee34e94a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 1 Apr 2016 09:53:44 -0700 Subject: [PATCH 025/110] Separate error messages for 'null', 'undefined', or both. --- src/compiler/checker.ts | 10 ++++++++-- src/compiler/diagnosticMessages.json | 10 +++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index da6548f8c69..6fc60c5c78a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9554,8 +9554,14 @@ namespace ts { function checkNonNullExpression(node: Expression | QualifiedName) { const type = checkExpression(node); - if (strictNullChecks && getNullableKind(type)) { - error(node, Diagnostics.Object_is_possibly_null_or_undefined); + if (strictNullChecks) { + const kind = getNullableKind(type); + if (kind) { + error(node, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ? + Diagnostics.Object_is_possibly_null_or_undefined : + Diagnostics.Object_is_possibly_undefined : + Diagnostics.Object_is_possibly_null); + } return getNonNullableType(type); } return type; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index d7c2fac2710..ebd3202d3a7 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1727,10 +1727,18 @@ "category": "Error", "code": 2530 }, - "Object is possibly 'null' or 'undefined'.": { + "Object is possibly 'null'.": { "category": "Error", "code": 2531 }, + "Object is possibly 'undefined'.": { + "category": "Error", + "code": 2532 + }, + "Object is possibly 'null' or 'undefined'.": { + "category": "Error", + "code": 2533 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 From fb0d720da71391b8a178630c6cac1ac7a1bd555c Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 7 Apr 2016 14:03:48 -0700 Subject: [PATCH 026/110] refactor cr --- src/server/editorServices.ts | 5 + src/server/session.ts | 320 ++++++++++++++++++----------------- 2 files changed, 166 insertions(+), 159 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 71907735b91..85285a4f3bd 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -464,6 +464,11 @@ namespace ts.server { return copiedList; } + export function forEachProject(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) { + const result = projects.reduce((previous, current) => concatenate(previous, action(current)), []).sort(comparer); + return projects.length > 1 ? deduplicate(result, areEqual) : result; + } + export interface ProjectServiceEventHandler { (eventName: string, project: Project, fileName: string): void; } diff --git a/src/server/session.ts b/src/server/session.ts index 199e6df21f4..db64d7edde2 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -141,8 +141,8 @@ namespace ts.server { ) { this.projectService = new ProjectService(host, logger, (eventName, project, fileName) => { - this.handleEvent(eventName, project, fileName); - }); + this.handleEvent(eventName, project, fileName); + }); } private handleEvent(eventName: string, project: Project, fileName: string) { @@ -412,11 +412,13 @@ namespace ts.server { private getRenameLocations(line: number, offset: number, fileName: string, findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { const file = ts.normalizePath(fileName); - const defaultProject = this.projectService.getProjectForFile(file); - if (!defaultProject) { + const info = this.projectService.getScriptInfo(file); + const projects = this.projectService.findReferencingProjects(info); + if (!projects.length) { throw Errors.NoProject; } + const defaultProject = projects[0]; // The rename info should be the same for every project const defaultProjectCompilerService = defaultProject.compilerService; const position = defaultProjectCompilerService.host.lineOffsetToPosition(file, line, offset); @@ -432,75 +434,73 @@ namespace ts.server { }; } - const locs: protocol.SpanGroup[] = []; - const info = this.projectService.getScriptInfo(file); - const projects = this.projectService.findReferencingProjects(info); - for (const project of projects) { - const compilerService = project.compilerService; - const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments); - if (!renameLocations) { - continue; - } - - const bakedRenameLocs = renameLocations.map(location => ({ - file: location.fileName, - start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start), - end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)), - })).sort((a, b) => { - if (a.file < b.file) { - return -1; + const fileSpans = forEachProject( + projects, + (project: Project) => { + const compilerService = project.compilerService; + const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments); + if (!renameLocations) { + return []; } - else if (a.file > b.file) { + + return renameLocations.map(location => ({ + file: location.fileName, + start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start), + end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)), + })); + }, + compareRenameLocation, + (a, b) => a.file === b.file && a.start.line === b.start.line && a.start.offset === b.start.offset + ); + const locs = fileSpans.reduce((accum, cur) => { + let curFileAccum: protocol.SpanGroup; + if (accum.length > 0) { + curFileAccum = accum[accum.length - 1]; + if (curFileAccum.file !== cur.file) { + curFileAccum = undefined; + } + } + if (!curFileAccum) { + curFileAccum = { file: cur.file, locs: [] }; + accum.push(curFileAccum); + } + curFileAccum.locs.push({ start: cur.start, end: cur.end }); + return accum; + }, []); + + return { info: renameInfo, locs }; + + function compareRenameLocation(a: protocol.FileSpan, b: protocol.FileSpan) { + if (a.file < b.file) { + return -1; + } + else if (a.file > b.file) { + return 1; + } + else { + // reverse sort assuming no overlap + if (a.start.line < b.start.line) { return 1; } + else if (a.start.line > b.start.line) { + return -1; + } else { - // reverse sort assuming no overlap - if (a.start.line < b.start.line) { - return 1; - } - else if (a.start.line > b.start.line) { - return -1; - } - else { - return b.start.offset - a.start.offset; - } + return b.start.offset - a.start.offset; } - }).reduce((accum: protocol.SpanGroup[], cur: protocol.FileSpan) => { - let curFileAccum: protocol.SpanGroup; - if (accum.length > 0) { - curFileAccum = accum[accum.length - 1]; - if (curFileAccum.file != cur.file) { - curFileAccum = undefined; - } - } - if (!curFileAccum) { - curFileAccum = { file: cur.file, locs: [] }; - accum.push(curFileAccum); - } - curFileAccum.locs.push({ start: cur.start, end: cur.end }); - return accum; - }, []); - - addRange(locs, bakedRenameLocs); - } - - return { info: renameInfo, locs: deduplicate(locs, areSpanGroupsForTheSameFile) }; - - function areSpanGroupsForTheSameFile(a: protocol.SpanGroup, b: protocol.SpanGroup) { - if (a && b) { - return a.file === b.file; } - return false; } } private getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody { const file = ts.normalizePath(fileName); - const defaultProject = this.projectService.getProjectForFile(file); - if (!defaultProject) { + const info = this.projectService.getScriptInfo(file); + const projects = this.projectService.findReferencingProjects(info); + if (!projects.length) { throw Errors.NoProject; } + const defaultProject = projects[0]; const position = defaultProject.compilerService.host.lineOffsetToPosition(file, line, offset); const nameInfo = defaultProject.compilerService.languageService.getQuickInfoAtPosition(file, position); if (!nameInfo) { @@ -511,34 +511,31 @@ namespace ts.server { const nameSpan = nameInfo.textSpan; const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset; const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); + const refs = forEachProject( + projects, + (project: Project) => { + const compilerService = project.compilerService; + const references = compilerService.languageService.getReferencesAtPosition(file, position); + if (!references) { + return []; + } - const info = this.projectService.getScriptInfo(file); - const projects = this.projectService.findReferencingProjects(info); - const refs: protocol.ReferencesResponseItem[] = []; - for (const project of projects) - { - const compilerService = project.compilerService; - const references = compilerService.languageService.getReferencesAtPosition(file, position); - if (!references) { - continue; - } - - const bakedRefs: protocol.ReferencesResponseItem[] = references.map(ref => { - const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start); - const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1); - const snap = compilerService.host.getScriptSnapshot(ref.fileName); - const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); - return { - file: ref.fileName, - start: start, - lineText: lineText, - end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)), - isWriteAccess: ref.isWriteAccess - }; - }).sort(compareFileStart); - - addRange(refs, bakedRefs); - } + return references.map(ref => { + const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start); + const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1); + const snap = compilerService.host.getScriptSnapshot(ref.fileName); + const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); + return { + file: ref.fileName, + start: start, + lineText: lineText, + end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)), + isWriteAccess: ref.isWriteAccess + }; + }); + }, + compareFileStart + ); return { refs: deduplicate(refs, areReferencesResponseItemsForTheSameLocation), @@ -550,8 +547,8 @@ namespace ts.server { function areReferencesResponseItemsForTheSameLocation(a: protocol.ReferencesResponseItem, b: protocol.ReferencesResponseItem) { if (a && b) { return a.file === b.file && - a.start === b.start && - a.end === b.end; + a.start === b.start && + a.end === b.end; } return false; } @@ -868,54 +865,57 @@ namespace ts.server { private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] { const file = ts.normalizePath(fileName); - const defaultProject = this.projectService.getProjectForFile(file); + const info = this.projectService.getScriptInfo(file); + const projects = this.projectService.findReferencingProjects(info); + const defaultProject = projects[0]; if (!defaultProject) { throw Errors.NoProject; } - const info = this.projectService.getScriptInfo(file); - const projects = this.projectService.findReferencingProjects(info); - const allNavToItems: protocol.NavtoItem[] = []; - for (const project of projects) { - const compilerService = project.compilerService; - const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount); - if (!navItems) { - continue; - } + const allNavToItems = forEachProject( + projects, + (project: Project) => { + const compilerService = project.compilerService; + const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount); + if (!navItems) { + return []; + } - const bakedNavItems = navItems.map((navItem) => { - const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start); - const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); - const bakedItem: protocol.NavtoItem = { - name: navItem.name, - kind: navItem.kind, - file: navItem.fileName, - start: start, - end: end, - }; - if (navItem.kindModifiers && (navItem.kindModifiers != "")) { - bakedItem.kindModifiers = navItem.kindModifiers; - } - if (navItem.matchKind !== "none") { - bakedItem.matchKind = navItem.matchKind; - } - if (navItem.containerName && (navItem.containerName.length > 0)) { - bakedItem.containerName = navItem.containerName; - } - if (navItem.containerKind && (navItem.containerKind.length > 0)) { - bakedItem.containerKind = navItem.containerKind; - } - return bakedItem; - }); - addRange(allNavToItems, bakedNavItems); - } - return deduplicate(allNavToItems, areNavToItemsForTheSameLocation); + return navItems.map((navItem) => { + const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start); + const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); + const bakedItem: protocol.NavtoItem = { + name: navItem.name, + kind: navItem.kind, + file: navItem.fileName, + start: start, + end: end, + }; + if (navItem.kindModifiers && (navItem.kindModifiers != "")) { + bakedItem.kindModifiers = navItem.kindModifiers; + } + if (navItem.matchKind !== "none") { + bakedItem.matchKind = navItem.matchKind; + } + if (navItem.containerName && (navItem.containerName.length > 0)) { + bakedItem.containerName = navItem.containerName; + } + if (navItem.containerKind && (navItem.containerKind.length > 0)) { + bakedItem.containerKind = navItem.containerKind; + } + return bakedItem; + }); + }, + /*comparer*/ undefined, + areNavToItemsForTheSameLocation + ); + return allNavToItems; function areNavToItemsForTheSameLocation(a: protocol.NavtoItem, b: protocol.NavtoItem) { if (a && b) { return a.file === b.file && - a.start === b.start && - a.end === b.end; + a.start === b.start && + a.end === b.end; } return false; } @@ -992,129 +992,131 @@ namespace ts.server { exit() { } - private handlers: Map<(request: protocol.Request) => {response?: any, responseRequired?: boolean}> = { + private handlers: Map<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = { [CommandNames.Exit]: () => { this.exit(); - return { responseRequired: false}; + return { responseRequired: false }; }, [CommandNames.Definition]: (request: protocol.Request) => { const defArgs = request.arguments; - return {response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true}; + return { response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true }; }, [CommandNames.TypeDefinition]: (request: protocol.Request) => { const defArgs = request.arguments; - return {response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true}; + return { response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true }; }, [CommandNames.References]: (request: protocol.Request) => { const defArgs = request.arguments; - return {response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true}; + return { response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true }; }, [CommandNames.Rename]: (request: protocol.Request) => { const renameArgs = request.arguments; - return {response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true}; + return { response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true }; }, [CommandNames.Open]: (request: protocol.Request) => { const openArgs = request.arguments; this.openClientFile(openArgs.file, openArgs.fileContent); - return {responseRequired: false}; + return { responseRequired: false }; }, [CommandNames.Quickinfo]: (request: protocol.Request) => { const quickinfoArgs = request.arguments; - return {response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file), responseRequired: true}; + return { response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file), responseRequired: true }; }, [CommandNames.Format]: (request: protocol.Request) => { const formatArgs = request.arguments; - return {response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file), responseRequired: true}; + return { response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file), responseRequired: true }; }, [CommandNames.Formatonkey]: (request: protocol.Request) => { const formatOnKeyArgs = request.arguments; - return {response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file), responseRequired: true}; + return { response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file), responseRequired: true }; }, [CommandNames.Completions]: (request: protocol.Request) => { const completionsArgs = request.arguments; - return {response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true}; + return { response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true }; }, [CommandNames.CompletionDetails]: (request: protocol.Request) => { const completionDetailsArgs = request.arguments; - return {response: this.getCompletionEntryDetails(completionDetailsArgs.line, completionDetailsArgs.offset, - completionDetailsArgs.entryNames, completionDetailsArgs.file), responseRequired: true}; + return { + response: this.getCompletionEntryDetails(completionDetailsArgs.line, completionDetailsArgs.offset, + completionDetailsArgs.entryNames, completionDetailsArgs.file), responseRequired: true + }; }, [CommandNames.SignatureHelp]: (request: protocol.Request) => { const signatureHelpArgs = request.arguments; - return {response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true}; + return { response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true }; }, [CommandNames.Geterr]: (request: protocol.Request) => { const geterrArgs = request.arguments; - return {response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false}; + return { response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false }; }, [CommandNames.GeterrForProject]: (request: protocol.Request) => { const { file, delay } = request.arguments; - return {response: this.getDiagnosticsForProject(delay, file), responseRequired: false}; + return { response: this.getDiagnosticsForProject(delay, file), responseRequired: false }; }, [CommandNames.Change]: (request: protocol.Request) => { const changeArgs = request.arguments; this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset, - changeArgs.insertString, changeArgs.file); - return {responseRequired: false}; + changeArgs.insertString, changeArgs.file); + return { responseRequired: false }; }, [CommandNames.Configure]: (request: protocol.Request) => { const configureArgs = request.arguments; this.projectService.setHostConfiguration(configureArgs); this.output(undefined, CommandNames.Configure, request.seq); - return {responseRequired: false}; + return { responseRequired: false }; }, [CommandNames.Reload]: (request: protocol.Request) => { const reloadArgs = request.arguments; this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq); - return {responseRequired: false}; + return { responseRequired: false }; }, [CommandNames.Saveto]: (request: protocol.Request) => { const savetoArgs = request.arguments; this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile); - return {responseRequired: false}; + return { responseRequired: false }; }, [CommandNames.Close]: (request: protocol.Request) => { const closeArgs = request.arguments; this.closeClientFile(closeArgs.file); - return {responseRequired: false}; + return { responseRequired: false }; }, [CommandNames.Navto]: (request: protocol.Request) => { const navtoArgs = request.arguments; - return {response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount), responseRequired: true}; + return { response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount), responseRequired: true }; }, [CommandNames.Brace]: (request: protocol.Request) => { const braceArguments = request.arguments; - return {response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file), responseRequired: true}; + return { response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file), responseRequired: true }; }, [CommandNames.NavBar]: (request: protocol.Request) => { const navBarArgs = request.arguments; - return {response: this.getNavigationBarItems(navBarArgs.file), responseRequired: true}; + return { response: this.getNavigationBarItems(navBarArgs.file), responseRequired: true }; }, [CommandNames.Occurrences]: (request: protocol.Request) => { const { line, offset, file: fileName } = request.arguments; - return {response: this.getOccurrences(line, offset, fileName), responseRequired: true}; + return { response: this.getOccurrences(line, offset, fileName), responseRequired: true }; }, [CommandNames.DocumentHighlights]: (request: protocol.Request) => { const { line, offset, file: fileName, filesToSearch } = request.arguments; - return {response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true}; + return { response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true }; }, [CommandNames.ProjectInfo]: (request: protocol.Request) => { const { file, needFileNameList } = request.arguments; - return {response: this.getProjectInfo(file, needFileNameList), responseRequired: true}; + return { response: this.getProjectInfo(file, needFileNameList), responseRequired: true }; }, [CommandNames.ReloadProjects]: (request: protocol.ReloadProjectsRequest) => { this.reloadProjects(); - return {responseRequired: false}; + return { responseRequired: false }; } }; - public addProtocolHandler(command: string, handler: (request: protocol.Request) => {response?: any, responseRequired: boolean}) { + public addProtocolHandler(command: string, handler: (request: protocol.Request) => { response?: any, responseRequired: boolean }) { if (this.handlers[command]) { throw new Error(`Protocol handler already exists for command "${command}"`); } this.handlers[command] = handler; } - public executeCommand(request: protocol.Request): {response?: any, responseRequired?: boolean} { + public executeCommand(request: protocol.Request): { response?: any, responseRequired?: boolean } { const handler = this.handlers[request.command]; if (handler) { return handler(request); @@ -1122,7 +1124,7 @@ namespace ts.server { else { this.projectService.log("Unrecognized JSON command: " + JSON.stringify(request)); this.output(undefined, CommandNames.Unknown, request.seq, "Unrecognized JSON command: " + request.command); - return {responseRequired: false}; + return { responseRequired: false }; } } From a2035a572eba0c98c79ba3dd952e1991d0123200 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 7 Apr 2016 23:01:20 -0700 Subject: [PATCH 027/110] Add API support for LS host to specify script kind of a file to open --- src/harness/fourslash.ts | 16 +++++++------- src/harness/harnessLanguageService.ts | 8 +++---- src/server/client.ts | 4 ++-- src/server/editorServices.ts | 20 +++++++++++++----- src/server/protocol.d.ts | 5 +++++ src/server/session.ts | 21 ++++++++++++++++--- src/services/utilities.ts | 11 ++++++---- tests/cases/fourslash/fourslash.ts | 4 ++-- .../server/openFileWithSyntaxKind.ts | 19 +++++++++++++++++ 9 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 tests/cases/fourslash/server/openFileWithSyntaxKind.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 44057cad327..1e58ab50996 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -358,14 +358,14 @@ namespace FourSlash { } // Opens a file given its 0-based index or fileName - public openFile(index: number, content?: string): void; - public openFile(name: string, content?: string): void; - public openFile(indexOrName: any, content?: string) { + public openFile(index: number, content?: string, scriptKindName?: string): void; + public openFile(name: string, content?: string, scriptKindName?: string): void; + public openFile(indexOrName: any, content?: string, scriptKindName?: string) { const fileToOpen: FourSlashFile = this.findFile(indexOrName); fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName); this.activeFile = fileToOpen; // Let the host know that this file is now open - this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content); + this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content, scriptKindName); } public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) { @@ -2755,10 +2755,10 @@ namespace FourSlashInterface { // Opens a file, given either its index as it // appears in the test source, or its filename // as specified in the test metadata - public file(index: number, content?: string): void; - public file(name: string, content?: string): void; - public file(indexOrName: any, content?: string): void { - this.state.openFile(indexOrName, content); + public file(index: number, content?: string, scriptKindName?: string): void; + public file(name: string, content?: string, scriptKindName?: string): void; + public file(indexOrName: any, content?: string, scriptKindName?: string): void { + this.state.openFile(indexOrName, content, scriptKindName); } } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 12bb6a470e4..d74c2fdeb8e 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -157,7 +157,7 @@ namespace Harness.LanguageService { throw new Error("No script with name '" + fileName + "'"); } - public openFile(fileName: string, content?: string): void { + public openFile(fileName: string, content?: string, scriptKindName?: string): void { } /** @@ -496,9 +496,9 @@ namespace Harness.LanguageService { this.client = client; } - openFile(fileName: string, content?: string): void { - super.openFile(fileName, content); - this.client.openFile(fileName, content); + openFile(fileName: string, content?: string, scriptKindName?: string): void { + super.openFile(fileName, content, scriptKindName); + this.client.openFile(fileName, content, scriptKindName); } editScript(fileName: string, start: number, end: number, newText: string) { diff --git a/src/server/client.ts b/src/server/client.ts index 957d36e4a3a..35fb0b11fbe 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -120,8 +120,8 @@ namespace ts.server { return response; } - openFile(fileName: string, content?: string): void { - var args: protocol.OpenRequestArgs = { file: fileName, fileContent: content }; + openFile(fileName: string, content?: string, scriptKindName?: string): void { + var args: protocol.OpenRequestArgs = { file: fileName, fileContent: content, scriptKindName }; this.processRequest(CommandNames.Open, args); } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 4b9f17798c8..443eb766e03 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -34,6 +34,7 @@ namespace ts.server { fileWatcher: FileWatcher; formatCodeOptions = ts.clone(CompilerService.defaultFormatCodeOptions); path: Path; + scriptKind: ScriptKind; constructor(private host: ServerHost, public fileName: string, public content: string, public isOpen = false) { this.path = toPath(fileName, host.getCurrentDirectory(), createGetCanonicalFileName(host.useCaseSensitiveFileNames)); @@ -192,8 +193,16 @@ namespace ts.server { return this.roots.map(root => root.fileName); } - getScriptKind() { - return ScriptKind.Unknown; + getScriptKind(fileName: string) { + const info = this.getScriptInfo(fileName); + if (!info) { + return undefined; + } + + if (!info.scriptKind) { + info.scriptKind = getScriptKindFromFileName(fileName); + } + return info.scriptKind; } getScriptVersion(filename: string) { @@ -988,7 +997,7 @@ namespace ts.server { * @param filename is absolute pathname * @param fileContent is a known version of the file content that is more up to date than the one on disk */ - openFile(fileName: string, openedByClient: boolean, fileContent?: string) { + openFile(fileName: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind) { fileName = ts.normalizePath(fileName); let info = ts.lookUp(this.filenameToScriptInfo, fileName); if (!info) { @@ -1003,6 +1012,7 @@ namespace ts.server { } if (content !== undefined) { info = new ScriptInfo(this.host, fileName, content, openedByClient); + info.scriptKind = scriptKind; info.setFormatOptions(this.getFormatCodeOptions()); this.filenameToScriptInfo[fileName] = info; if (!info.isOpen) { @@ -1052,9 +1062,9 @@ namespace ts.server { * @param filename is absolute pathname * @param fileContent is a known version of the file content that is more up to date than the one on disk */ - openClientFile(fileName: string, fileContent?: string) { + openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind) { this.openOrUpdateConfiguredProjectForFile(fileName); - const info = this.openFile(fileName, /*openedByClient*/ true, fileContent); + const info = this.openFile(fileName, /*openedByClient*/ true, fileContent, scriptKind); this.addOpenFile(info); this.printProjects(); return info; diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index 5ed227ebaa7..d6ff438a1c0 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -518,6 +518,11 @@ declare namespace ts.server.protocol { * Then the known content will be used upon opening instead of the disk copy */ fileContent?: string; + /** + * Used to specify the script kind of the file explicitly. It could be one of the following: + * ".ts", ".js", ".tsx", ".jsx" + */ + scriptKindName?: string; } /** diff --git a/src/server/session.ts b/src/server/session.ts index f0975a3f947..6dd74e8985b 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -529,9 +529,9 @@ namespace ts.server { * @param fileName is the name of the file to be opened * @param fileContent is a version of the file content that is known to be more up to date than the one on disk */ - private openClientFile(fileName: string, fileContent?: string) { + private openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind) { const file = ts.normalizePath(fileName); - this.projectService.openClientFile(file, fileContent); + this.projectService.openClientFile(file, fileContent, scriptKind); } private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody { @@ -967,7 +967,22 @@ namespace ts.server { }, [CommandNames.Open]: (request: protocol.Request) => { const openArgs = request.arguments; - this.openClientFile(openArgs.file, openArgs.fileContent); + let scriptKind: ScriptKind; + switch (openArgs.scriptKindName) { + case ".ts": + scriptKind = ScriptKind.TS; + break; + case ".js": + scriptKind = ScriptKind.JS; + break; + case ".tsx": + scriptKind = ScriptKind.TSX; + break; + case ".jsx": + scriptKind = ScriptKind.JSX; + break; + } + this.openClientFile(openArgs.file, openArgs.fileContent, scriptKind); return {responseRequired: false}; }, [CommandNames.Quickinfo]: (request: protocol.Request) => { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 4d29cd99e12..332762a55dd 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -818,12 +818,15 @@ namespace ts { } export function getScriptKind(fileName: string, host?: LanguageServiceHost): ScriptKind { - // First check to see if the script kind can be determined from the file name - var scriptKind = getScriptKindFromFileName(fileName); - if (scriptKind === ScriptKind.Unknown && host && host.getScriptKind) { - // Next check to see if the host can resolve the script kind + // First check to see if the script kind was specified by the host. Chances are the host + // may override the default script kind for the file extension. + let scriptKind: ScriptKind; + if (host && host.getScriptKind) { scriptKind = host.getScriptKind(fileName); } + if (!scriptKind || scriptKind === ScriptKind.Unknown) { + scriptKind = getScriptKindFromFileName(fileName); + } return ensureScriptKind(fileName, scriptKind); } } \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index b69a757f01e..0e379017d08 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -110,8 +110,8 @@ declare namespace FourSlashInterface { type(definitionIndex?: number): void; position(position: number, fileIndex?: number): any; position(position: number, fileName?: string): any; - file(index: number, content?: string): any; - file(name: string, content?: string): any; + file(index: number, content?: string, scriptKindName?: string): any; + file(name: string, content?: string, scriptKindName?: string): any; } class verifyNegatable { private negative; diff --git a/tests/cases/fourslash/server/openFileWithSyntaxKind.ts b/tests/cases/fourslash/server/openFileWithSyntaxKind.ts new file mode 100644 index 00000000000..006e5490b6f --- /dev/null +++ b/tests/cases/fourslash/server/openFileWithSyntaxKind.ts @@ -0,0 +1,19 @@ +/// + +// Because the fourslash runner automatically opens the first file with the default setting, +// to test the openFile function, the targeted file cannot be the first one. + +// @Filename: dumbFile.ts +//// var x; + +// @allowJs: true +// @Filename: test.ts +//// /** +//// * @type {number} +//// */ +//// var t; +//// t. + +goTo.file("test.ts", /*content*/ undefined, ".js"); +goTo.eof(); +verify.completionListContains("toExponential"); From 5179dd6ada16a9b0eaf1e84eb9453df8e4772aaa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Apr 2016 09:13:47 -0700 Subject: [PATCH 028/110] Flow analysis of &&, ||, and destructuring assignments --- src/compiler/binder.ts | 285 +++++++++++++++++++++++++++----------- src/compiler/checker.ts | 179 ++++++++++-------------- src/compiler/types.ts | 6 +- src/compiler/utilities.ts | 25 ++++ 4 files changed, 305 insertions(+), 190 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index cfeb76827bf..39dca4070a7 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -105,8 +105,10 @@ namespace ts { // state used by reachability checks let hasExplicitReturn: boolean; let currentFlow: FlowNode; - let breakTarget: FlowLabel; - let continueTarget: FlowLabel; + let currentBreakTarget: FlowLabel; + let currentContinueTarget: FlowLabel; + let currentTrueTarget: FlowLabel; + let currentFalseTarget: FlowLabel; let preSwitchCaseFlow: FlowNode; let activeLabels: ActiveLabel[]; @@ -151,8 +153,10 @@ namespace ts { seenThisKeyword = false; hasExplicitReturn = false; currentFlow = undefined; - breakTarget = undefined; - continueTarget = undefined; + currentBreakTarget = undefined; + currentContinueTarget = undefined; + currentTrueTarget = undefined; + currentFalseTarget = undefined; activeLabels = undefined; hasClassExtends = false; hasAsyncFunctions = false; @@ -437,6 +441,8 @@ namespace ts { let savedCurrentFlow: FlowNode; let savedBreakTarget: FlowLabel; let savedContinueTarget: FlowLabel; + let savedTrueTarget: FlowLabel; + let savedFalseTarget: FlowLabel; let savedActiveLabels: ActiveLabel[]; const kind = node.kind; @@ -456,14 +462,14 @@ namespace ts { if (saveState) { savedHasExplicitReturn = hasExplicitReturn; savedCurrentFlow = currentFlow; - savedBreakTarget = breakTarget; - savedContinueTarget = continueTarget; + savedBreakTarget = currentBreakTarget; + savedContinueTarget = currentContinueTarget; savedActiveLabels = activeLabels; hasExplicitReturn = false; currentFlow = { kind: FlowKind.Start }; - breakTarget = undefined; - continueTarget = undefined; + currentBreakTarget = undefined; + currentContinueTarget = undefined; activeLabels = undefined; } @@ -502,11 +508,11 @@ namespace ts { node.flags = flags; if (saveState) { - activeLabels = savedActiveLabels; - continueTarget = savedContinueTarget; - breakTarget = savedBreakTarget; - currentFlow = savedCurrentFlow; hasExplicitReturn = savedHasExplicitReturn; + currentFlow = savedCurrentFlow; + currentBreakTarget = savedBreakTarget; + currentContinueTarget = savedContinueTarget; + activeLabels = savedActiveLabels; } container = saveContainer; @@ -561,6 +567,9 @@ namespace ts { case SyntaxKind.LabeledStatement: bindLabeledStatement(node); break; + case SyntaxKind.PrefixUnaryExpression: + bindPrefixUnaryExpressionFlow(node); + break; case SyntaxKind.BinaryExpression: bindBinaryExpressionFlow(node); break; @@ -613,9 +622,6 @@ namespace ts { return true; } return false; - case SyntaxKind.AmpersandAmpersandToken: - case SyntaxKind.BarBarToken: - return isNarrowingExpression(expr.left) || isNarrowingExpression(expr.right); case SyntaxKind.InstanceOfKeyword: return isNarrowingExpression(expr.left); } @@ -656,7 +662,7 @@ namespace ts { }; } - function createFlowAssignment(antecedent: FlowNode, node: BinaryExpression | VariableDeclaration | ForInStatement | ForOfStatement): FlowNode { + function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode { return { kind: FlowKind.Assignment, antecedent, @@ -678,21 +684,78 @@ namespace ts { return flow; } + function isStatementCondition(node: Node) { + const parent = node.parent; + switch (parent.kind) { + case SyntaxKind.IfStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.DoStatement: + return (parent).expression === node; + case SyntaxKind.ForStatement: + case SyntaxKind.ConditionalExpression: + return (parent).condition === node; + } + return false; + } + + function isLogicalExpression(node: Node) { + while (true) { + if (node.kind === SyntaxKind.ParenthesizedExpression) { + node = (node).expression; + } + else if (node.kind === SyntaxKind.PrefixUnaryExpression && (node).operator === SyntaxKind.ExclamationToken) { + node = (node).operand; + } + else { + return node.kind === SyntaxKind.BinaryExpression && ( + (node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || + (node).operatorToken.kind === SyntaxKind.BarBarToken); + } + } + } + + function isTopLevelLogicalExpression(node: Node): boolean { + while (node.parent.kind === SyntaxKind.ParenthesizedExpression || + node.parent.kind === SyntaxKind.PrefixUnaryExpression && + (node.parent).operator === SyntaxKind.ExclamationToken) { + node = node.parent; + } + return !isStatementCondition(node) && !isLogicalExpression(node.parent); + } + + function bindCondition(node: Expression, trueTarget: FlowLabel, falseTarget: FlowLabel) { + const saveTrueTarget = currentTrueTarget; + const saveFalseTarget = currentFalseTarget; + currentTrueTarget = trueTarget; + currentFalseTarget = falseTarget; + bind(node); + currentTrueTarget = saveTrueTarget; + currentFalseTarget = saveFalseTarget; + if (!node || !isLogicalExpression(node)) { + addAntecedent(trueTarget, createFlowCondition(currentFlow, node, /*assumeTrue*/ true)); + addAntecedent(falseTarget, createFlowCondition(currentFlow, node, /*assumeTrue*/ false)); + } + } + + function bindIterativeStatement(node: Statement, breakTarget: FlowLabel, continueTarget: FlowLabel): void { + const saveBreakTarget = currentBreakTarget; + const saveContinueTarget = currentContinueTarget; + currentBreakTarget = breakTarget; + currentContinueTarget = continueTarget; + bind(node); + currentBreakTarget = saveBreakTarget; + currentContinueTarget = saveContinueTarget; + } + function bindWhileStatement(node: WhileStatement): void { const preWhileLabel = createFlowLabel(); + const preBodyLabel = createFlowLabel(); const postWhileLabel = createFlowLabel(); addAntecedent(preWhileLabel, currentFlow); currentFlow = preWhileLabel; - bind(node.expression); - addAntecedent(postWhileLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ false)); - currentFlow = createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ true); - const saveBreakTarget = breakTarget; - const saveContinueTarget = continueTarget; - breakTarget = postWhileLabel; - continueTarget = preWhileLabel; - bind(node.statement); - breakTarget = saveBreakTarget; - continueTarget = saveContinueTarget; + bindCondition(node.expression, preBodyLabel, postWhileLabel); + currentFlow = finishFlow(preBodyLabel); + bindIterativeStatement(node.statement, postWhileLabel, preWhileLabel); addAntecedent(preWhileLabel, currentFlow); currentFlow = finishFlow(postWhileLabel); } @@ -703,38 +766,24 @@ namespace ts { const postDoLabel = createFlowLabel(); addAntecedent(preDoLabel, currentFlow); currentFlow = preDoLabel; - const saveBreakTarget = breakTarget; - const saveContinueTarget = continueTarget; - breakTarget = postDoLabel; - continueTarget = preConditionLabel; - bind(node.statement); - breakTarget = saveBreakTarget; - continueTarget = saveContinueTarget; + bindIterativeStatement(node.statement, postDoLabel, preConditionLabel); addAntecedent(preConditionLabel, currentFlow); currentFlow = finishFlow(preConditionLabel); - bind(node.expression); - addAntecedent(preDoLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ true)); - addAntecedent(postDoLabel, createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ false)); + bindCondition(node.expression, preDoLabel, postDoLabel); currentFlow = finishFlow(postDoLabel); } function bindForStatement(node: ForStatement): void { const preLoopLabel = createFlowLabel(); + const preBodyLabel = createFlowLabel(); const postLoopLabel = createFlowLabel(); bind(node.initializer); addAntecedent(preLoopLabel, currentFlow); currentFlow = preLoopLabel; - bind(node.condition); - addAntecedent(postLoopLabel, createFlowCondition(currentFlow, node.condition, /*assumeTrue*/ false)); - currentFlow = createFlowCondition(currentFlow, node.condition, /*assumeTrue*/ true); - const saveBreakTarget = breakTarget; - const saveContinueTarget = continueTarget; - breakTarget = postLoopLabel; - continueTarget = preLoopLabel; - bind(node.statement); + bindCondition(node.condition, preBodyLabel, postLoopLabel); + currentFlow = finishFlow(preBodyLabel); + bindIterativeStatement(node.statement, postLoopLabel, preLoopLabel); bind(node.incrementor); - breakTarget = saveBreakTarget; - continueTarget = saveContinueTarget; addAntecedent(preLoopLabel, currentFlow); currentFlow = finishFlow(postLoopLabel); } @@ -742,31 +791,28 @@ namespace ts { function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void { const preLoopLabel = createFlowLabel(); const postLoopLabel = createFlowLabel(); - bind(node.initializer); addAntecedent(preLoopLabel, currentFlow); currentFlow = preLoopLabel; bind(node.expression); addAntecedent(postLoopLabel, currentFlow); - const saveBreakTarget = breakTarget; - const saveContinueTarget = continueTarget; - breakTarget = postLoopLabel; - continueTarget = preLoopLabel; - currentFlow = createFlowAssignment(currentFlow, node); - bind(node.statement); - breakTarget = saveBreakTarget; - continueTarget = saveContinueTarget; + bind(node.initializer); + if (node.initializer.kind !== SyntaxKind.VariableDeclarationList) { + bindAssignmentTargetFlow(node.initializer); + } + bindIterativeStatement(node.statement, postLoopLabel, preLoopLabel); addAntecedent(preLoopLabel, currentFlow); currentFlow = finishFlow(postLoopLabel); } function bindIfStatement(node: IfStatement): void { + const thenLabel = createFlowLabel(); + const elseLabel = createFlowLabel(); const postIfLabel = createFlowLabel(); - bind(node.expression); - const postConditionFlow = currentFlow; - currentFlow = createFlowCondition(currentFlow, node.expression, /*assumeTrue*/ true); + bindCondition(node.expression, thenLabel, elseLabel); + currentFlow = finishFlow(thenLabel); bind(node.thenStatement); addAntecedent(postIfLabel, currentFlow); - currentFlow = createFlowCondition(postConditionFlow, node.expression, /*assumeTrue*/ false); + currentFlow = finishFlow(elseLabel); bind(node.elseStatement); addAntecedent(postIfLabel, currentFlow); currentFlow = finishFlow(postIfLabel); @@ -809,7 +855,7 @@ namespace ts { } } else { - bindbreakOrContinueFlow(node, breakTarget, continueTarget); + bindbreakOrContinueFlow(node, currentBreakTarget, currentContinueTarget); } } @@ -834,9 +880,9 @@ namespace ts { function bindSwitchStatement(node: SwitchStatement): void { const postSwitchLabel = createFlowLabel(); bind(node.expression); - const saveBreakTarget = breakTarget; + const saveBreakTarget = currentBreakTarget; const savePreSwitchCaseFlow = preSwitchCaseFlow; - breakTarget = postSwitchLabel; + currentBreakTarget = postSwitchLabel; preSwitchCaseFlow = currentFlow; bind(node.caseBlock); addAntecedent(postSwitchLabel, currentFlow); @@ -844,7 +890,7 @@ namespace ts { if (!hasDefault) { addAntecedent(postSwitchLabel, preSwitchCaseFlow); } - breakTarget = saveBreakTarget; + currentBreakTarget = saveBreakTarget; preSwitchCaseFlow = savePreSwitchCaseFlow; currentFlow = finishFlow(postSwitchLabel); } @@ -904,43 +950,118 @@ namespace ts { currentFlow = finishFlow(postStatementLabel); } - function bindBinaryExpressionFlow(node: BinaryExpression) { - const operator = node.operatorToken.kind; - if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) { - const postExpressionLabel = createFlowLabel(); - bind(node.left); - bind(node.operatorToken); - addAntecedent(postExpressionLabel, currentFlow); - currentFlow = createFlowCondition(currentFlow, node.left, /*assumeTrue*/ operator === SyntaxKind.AmpersandAmpersandToken); - bind(node.right); - addAntecedent(postExpressionLabel, currentFlow); - currentFlow = finishFlow(postExpressionLabel); + function bindDestructuringTargetFlow(node: Expression) { + if (node.kind === SyntaxKind.BinaryExpression && (node).operatorToken.kind === SyntaxKind.EqualsToken) { + bindAssignmentTargetFlow((node).left); + } + else { + bindAssignmentTargetFlow(node); + } + } + + function bindAssignmentTargetFlow(node: Expression) { + if (isNarrowableReference(node)) { + currentFlow = createFlowAssignment(currentFlow, node); + } + else if (node.kind === SyntaxKind.ArrayLiteralExpression) { + for (const e of (node).elements) { + if (e.kind === SyntaxKind.SpreadElementExpression) { + bindAssignmentTargetFlow((e).expression); + } + else { + bindDestructuringTargetFlow(e); + } + } + } + else if (node.kind === SyntaxKind.ObjectLiteralExpression) { + for (const p of (node).properties) { + if (p.kind === SyntaxKind.PropertyAssignment) { + bindDestructuringTargetFlow((p).initializer); + } + else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { + bindAssignmentTargetFlow((p).name); + } + } + } + } + + function bindLogicalExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) { + const preRightLabel = createFlowLabel(); + if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { + bindCondition(node.left, preRightLabel, falseTarget); + } + else { + bindCondition(node.left, trueTarget, preRightLabel); + } + currentFlow = finishFlow(preRightLabel); + bind(node.operatorToken); + bindCondition(node.right, trueTarget, falseTarget); + } + + function bindPrefixUnaryExpressionFlow(node: PrefixUnaryExpression) { + if (node.operator === SyntaxKind.ExclamationToken) { + const saveTrueTarget = currentTrueTarget; + currentTrueTarget = currentFalseTarget; + currentFalseTarget = saveTrueTarget; + forEachChild(node, bind); + currentFalseTarget = currentTrueTarget; + currentTrueTarget = saveTrueTarget; } else { forEachChild(node, bind); - if (operator === SyntaxKind.EqualsToken) { - currentFlow = createFlowAssignment(currentFlow, node); + } + } + + function bindBinaryExpressionFlow(node: BinaryExpression) { + const operator = node.operatorToken.kind; + if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) { + if (isTopLevelLogicalExpression(node)) { + const postExpressionLabel = createFlowLabel(); + bindLogicalExpression(node, postExpressionLabel, postExpressionLabel); + currentFlow = finishFlow(postExpressionLabel); + } + else { + bindLogicalExpression(node, currentTrueTarget, currentFalseTarget); + } + } + else { + forEachChild(node, bind); + if (operator === SyntaxKind.EqualsToken && !isAssignmentTarget(node)) { + bindAssignmentTargetFlow(node.left); } } } function bindConditionalExpressionFlow(node: ConditionalExpression) { + const trueLabel = createFlowLabel(); + const falseLabel = createFlowLabel(); const postExpressionLabel = createFlowLabel(); - bind(node.condition); - const postConditionFlow = currentFlow; - currentFlow = createFlowCondition(currentFlow, node.condition, /*assumeTrue*/ true); + bindCondition(node.condition, trueLabel, falseLabel); + currentFlow = finishFlow(trueLabel); bind(node.whenTrue); addAntecedent(postExpressionLabel, currentFlow); - currentFlow = createFlowCondition(postConditionFlow, node.condition, /*assumeTrue*/ false); + currentFlow = finishFlow(falseLabel); bind(node.whenFalse); addAntecedent(postExpressionLabel, currentFlow); currentFlow = finishFlow(postExpressionLabel); } + function bindInitializedVariableFlow(node: VariableDeclaration | BindingElement) { + const name = node.name; + if (isBindingPattern(name)) { + for (const child of name.elements) { + bindInitializedVariableFlow(child); + } + } + else { + currentFlow = createFlowAssignment(currentFlow, node); + } + } + function bindVariableDeclarationFlow(node: VariableDeclaration) { forEachChild(node, bind); - if (node.initializer) { - currentFlow = createFlowAssignment(currentFlow, node); + if (node.initializer || node.parent.parent.kind === SyntaxKind.ForInStatement || node.parent.parent.kind === SyntaxKind.ForOfStatement) { + bindInitializedVariableFlow(node); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6fc60c5c78a..2393b236648 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7335,6 +7335,59 @@ namespace ts { return firstType ? types ? getUnionType(types, /*noSubtypeReduction*/ true) : firstType : emptyUnionType; } + function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { + const type = checkExpressionCached(node.right); + const parent = node.parent; + if (parent.kind === SyntaxKind.ArrayLiteralExpression || parent.kind === SyntaxKind.PropertyAssignment) { + const assignedType = getAssignedType(node); + return getUnionType([getTypeWithFacts(assignedType, TypeFacts.NEUndefined), type]); + } + return type; + } + + function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { + const arrayLikeType = getAssignedType(node); + const elementType = checkIteratedTypeOrElementType(arrayLikeType, node, /*allowStringInput*/ false); + const propName = "" + indexOf(node.elements, element); + return isTupleLikeType(arrayLikeType) && getTypeOfPropertyOfType(arrayLikeType, propName) || elementType; + } + + function getAssignedTypeOfSpreadElement(node: SpreadElementExpression): Type { + const arrayLikeType = getAssignedType(node.parent); + const elementType = checkIteratedTypeOrElementType(arrayLikeType, node, /*allowStringInput*/ false); + return createArrayType(elementType); + } + + function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment): Type { + const objectType = getAssignedType(node.parent); + const text = getTextOfPropertyName(node.name); + return getTypeOfPropertyOfType(objectType, text) || + isNumericLiteralName(text) && getIndexTypeOfType(objectType, IndexKind.Number) || + getIndexTypeOfType(objectType, IndexKind.String) || + unknownType; + } + + function getAssignedType(node: Expression): Type { + const parent = node.parent; + switch (parent.kind) { + case SyntaxKind.ForInStatement: + return stringType; + case SyntaxKind.ForOfStatement: + return checkRightHandSideOfForOf((parent).expression); + case SyntaxKind.BinaryExpression: + return getAssignedTypeOfBinaryExpression(parent); + case SyntaxKind.ArrayLiteralExpression: + return getAssignedTypeOfArrayLiteralElement(parent, node); + case SyntaxKind.SpreadElementExpression: + return getAssignedTypeOfSpreadElement(parent); + case SyntaxKind.PropertyAssignment: + return getAssignedTypeOfPropertyAssignment(parent); + case SyntaxKind.ShorthandPropertyAssignment: + break; // !!! TODO + } + return unknownType; + } + function getNarrowedTypeOfReference(type: Type, reference: Node) { if (!(type.flags & TypeFlags.Narrowable) || !isNarrowableReference(reference)) { return type; @@ -7384,58 +7437,34 @@ namespace ts { } } - function getTypeAtVariableDeclaration(node: VariableDeclaration) { - if (reference.kind === SyntaxKind.Identifier && !isBindingPattern(node.name) && getResolvedSymbol(reference) === getSymbolOfNode(node)) { - return getAssignmentReducedType(declaredType, checkExpressionCached((node).initializer)); - } - return undefined; - } - - function getTypeAtForInOrForOfStatement(node: ForInStatement | ForOfStatement) { - if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { - if (reference.kind === SyntaxKind.Identifier) { - const variable = (node.initializer).declarations[0]; - if (variable && !isBindingPattern(variable.name) && getResolvedSymbol(reference) === getSymbolOfNode(variable)) { - return declaredType; - } - } - } - else { - if (isMatchingReference(reference, node.initializer)) { - const type = node.kind === SyntaxKind.ForOfStatement ? checkRightHandSideOfForOf(node.expression) : stringType; - return getAssignmentReducedType(declaredType, type); - } - if (reference.kind === SyntaxKind.PropertyAccessExpression && - containsMatchingReference((reference).expression, node.initializer)) { - return declaredType; + function getTypeAtVariableDeclaration(node: VariableDeclaration | BindingElement) { + if (reference.kind === SyntaxKind.Identifier && getResolvedSymbol(reference) === getSymbolOfNode(node)) { + if (node.initializer) { + return getAssignmentReducedType(declaredType, checkExpressionCached(node.initializer)); } + return declaredType; // !!! TODO } return undefined; } function getTypeAtFlowAssignment(flow: FlowAssignment) { const node = flow.node; - switch (node.kind) { - case SyntaxKind.BinaryExpression: - // If reference matches left hand side and type on right is properly assignable, - // return type on right. Otherwise default to the declared type. - if (isMatchingReference(reference, (node).left)) { - return getAssignmentReducedType(declaredType, checkExpressionCached((node).right)); - } - // We didn't have a direct match. However, if the reference is a dotted name, this - // may be an assignment to a left hand part of the reference. For example, for a - // reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case, - // return the declared type. - if (reference.kind === SyntaxKind.PropertyAccessExpression && - containsMatchingReference((reference).expression, (node).left)) { - return declaredType; - } - break; - case SyntaxKind.VariableDeclaration: - return getTypeAtVariableDeclaration(node); - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - return getTypeAtForInOrForOfStatement(node); + if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { + return getTypeAtVariableDeclaration(node); + } + // If the node is not a variable declaration or binding element, it is an identifier + // or a dotted name that is the target of an assignment. If we have a match, reduce + // the declared type by the assigned type. + if (isMatchingReference(reference, node)) { + return getAssignmentReducedType(declaredType, getAssignedType(node)); + } + // We didn't have a direct match. However, if the reference is a dotted name, this + // may be an assignment to a left hand part of the reference. For example, for a + // reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case, + // return the declared type. + if (reference.kind === SyntaxKind.PropertyAccessExpression && + containsMatchingReference((reference).expression, node)) { + return declaredType; } // Assignment doesn't affect reference return undefined; @@ -7503,10 +7532,6 @@ namespace ts { return narrowTypeByTypeof(type, expr, assumeTrue); } break; - case SyntaxKind.AmpersandAmpersandToken: - return narrowTypeByAnd(type, expr, assumeTrue); - case SyntaxKind.BarBarToken: - return narrowTypeByOr(type, expr, assumeTrue); case SyntaxKind.InstanceOfKeyword: return narrowTypeByInstanceof(type, expr, assumeTrue); } @@ -7558,36 +7583,6 @@ namespace ts { return getTypeWithFacts(type, facts); } - function narrowTypeByAnd(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { - if (assumeTrue) { - // The assumed result is true, therefore we narrow assuming each operand to be true. - return narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true); - } - else { - // The assumed result is false. This means either the first operand was false, or the first operand was true - // and the second operand was false. We narrow with those assumptions and union the two resulting types. - return getUnionType([ - narrowType(type, expr.left, /*assumeTrue*/ false), - narrowType(type, expr.right, /*assumeTrue*/ false) - ]); - } - } - - function narrowTypeByOr(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { - if (assumeTrue) { - // The assumed result is true. This means either the first operand was true, or the first operand was false - // and the second operand was true. We narrow with those assumptions and union the two resulting types. - return getUnionType([ - narrowType(type, expr.left, /*assumeTrue*/ true), - narrowType(type, expr.right, /*assumeTrue*/ true) - ]); - } - else { - // The assumed result is false, therefore we narrow assuming each operand to be false. - return narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ false); - } - } - function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { // Check that type is not any, assumed result is true, and we have variable symbol on the left if (isTypeAny(type) || !isMatchingReference(expr.left, reference)) { @@ -8718,32 +8713,6 @@ namespace ts { return mapper && mapper.context; } - // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property - // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is - // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'. - function isAssignmentTarget(node: Node): boolean { - while (node.parent.kind === SyntaxKind.ParenthesizedExpression) { - node = node.parent; - } - while (true) { - if (node.parent.kind === SyntaxKind.PropertyAssignment) { - node = node.parent.parent; - } - else if (node.parent.kind === SyntaxKind.ArrayLiteralExpression) { - node = node.parent; - } - else { - break; - } - } - const parent = node.parent; - return parent.kind === SyntaxKind.BinaryExpression && - (parent).operatorToken.kind === SyntaxKind.EqualsToken && - (parent).left === node || - (parent.kind === SyntaxKind.ForInStatement || parent.kind === SyntaxKind.ForOfStatement) && - (parent).initializer === node; - } - function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type { // It is usually not safe to call checkExpressionCached if we can be contextually typing. // You can tell that we are contextually typing because of the contextualMapper parameter. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ed82d65d5dd..7deee80476b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1537,10 +1537,10 @@ namespace ts { antecedents: FlowNode[]; } - // FlowAssignment represents a node that possibly assigns a value to one or more - // references. + // FlowAssignment represents a node that assigns a value to a narrowable reference, + // i.e. an identifier or a dotted name that starts with an identifier or 'this'. export interface FlowAssignment extends FlowNode { - node: BinaryExpression | VariableDeclaration | ForInStatement | ForOfStatement; + node: Expression | VariableDeclaration | BindingElement; antecedent: FlowNode; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index da33c18dfb8..45567538dcd 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1316,6 +1316,31 @@ namespace ts { return !!node && (node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern); } + // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property + // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is + // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'. + export function isAssignmentTarget(node: Node): boolean { + while (node.parent.kind === SyntaxKind.ParenthesizedExpression) { + node = node.parent; + } + while (true) { + const parent = node.parent; + if (parent.kind === SyntaxKind.ArrayLiteralExpression || parent.kind === SyntaxKind.SpreadElementExpression) { + node = parent; + continue; + } + if (parent.kind === SyntaxKind.PropertyAssignment) { + node = parent.parent; + continue; + } + return parent.kind === SyntaxKind.BinaryExpression && + (parent).operatorToken.kind === SyntaxKind.EqualsToken && + (parent).left === node || + (parent.kind === SyntaxKind.ForInStatement || parent.kind === SyntaxKind.ForOfStatement) && + (parent).initializer === node; + } + } + export function isNodeDescendentOf(node: Node, ancestor: Node): boolean { while (node) { if (node === ancestor) return true; From 019f5bd4e8247464b003a124fcb74caa9f582eb1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Apr 2016 09:21:17 -0700 Subject: [PATCH 029/110] Accepting new baselines --- .../reference/restElementWithAssignmentPattern5.types | 2 +- ...tionDestructuringForArrayBindingPatternDefaultValues.types | 2 +- tests/baselines/reference/typeGuardOfFormInstanceOf.types | 4 ++-- .../reference/typeGuardOfFormInstanceOfOnInterface.types | 4 ++-- tests/baselines/reference/typeGuardOfFormIsType.types | 4 ++-- .../reference/typeGuardOfFormIsTypeOnInterfaces.types | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/baselines/reference/restElementWithAssignmentPattern5.types b/tests/baselines/reference/restElementWithAssignmentPattern5.types index e3934c31197..c5cbc9ad206 100644 --- a/tests/baselines/reference/restElementWithAssignmentPattern5.types +++ b/tests/baselines/reference/restElementWithAssignmentPattern5.types @@ -7,7 +7,7 @@ var s: string, s2: string; >[...[s, s2]] = ["", ""] : string[] >[...[s, s2]] : string[] >...[s, s2] : string ->[s, s2] : string[] +>[s, s2] : [string, string] >s : string >s2 : string >["", ""] : string[] diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types index 245328296eb..102e784aa91 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types @@ -595,5 +595,5 @@ for (let [numberA3 = -1, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0; i < >console.log : (msg: any) => void >console : { log(msg: any): void; } >log : (msg: any) => void ->numberA3 : number | string +>numberA3 : number } diff --git a/tests/baselines/reference/typeGuardOfFormInstanceOf.types b/tests/baselines/reference/typeGuardOfFormInstanceOf.types index 6b83b57dcb5..608e827f479 100644 --- a/tests/baselines/reference/typeGuardOfFormInstanceOf.types +++ b/tests/baselines/reference/typeGuardOfFormInstanceOf.types @@ -60,7 +60,7 @@ num = ctor1 instanceof C2 && ctor1.p2; // C2 >num : number >ctor1 instanceof C2 && ctor1.p2 : number >ctor1 instanceof C2 : boolean ->ctor1 : C1 | C2 +>ctor1 : C2 | C1 >C2 : typeof C2 >ctor1.p2 : number >ctor1 : C2 @@ -109,7 +109,7 @@ num = ctor2 instanceof D1 && ctor2.p3; // D1 >num : number >ctor2 instanceof D1 && ctor2.p3 : number >ctor2 instanceof D1 : boolean ->ctor2 : C2 | D1 +>ctor2 : D1 | C2 >D1 : typeof D1 >ctor2.p3 : number >ctor2 : D1 diff --git a/tests/baselines/reference/typeGuardOfFormInstanceOfOnInterface.types b/tests/baselines/reference/typeGuardOfFormInstanceOfOnInterface.types index 20d1c1644fc..a5387e66d44 100644 --- a/tests/baselines/reference/typeGuardOfFormInstanceOfOnInterface.types +++ b/tests/baselines/reference/typeGuardOfFormInstanceOfOnInterface.types @@ -84,7 +84,7 @@ num = c1Orc2 instanceof c2 && c1Orc2.p2; // C2 >num : number >c1Orc2 instanceof c2 && c1Orc2.p2 : number >c1Orc2 instanceof c2 : boolean ->c1Orc2 : C1 | C2 +>c1Orc2 : C2 | C1 >c2 : C2 >c1Orc2.p2 : number >c1Orc2 : C2 @@ -133,7 +133,7 @@ num = c2Ord1 instanceof d1 && c2Ord1.p3; // D1 >num : number >c2Ord1 instanceof d1 && c2Ord1.p3 : number >c2Ord1 instanceof d1 : boolean ->c2Ord1 : C2 | D1 +>c2Ord1 : D1 | C2 >d1 : D1 >c2Ord1.p3 : number >c2Ord1 : D1 diff --git a/tests/baselines/reference/typeGuardOfFormIsType.types b/tests/baselines/reference/typeGuardOfFormIsType.types index e2059be7b63..23ce38732cd 100644 --- a/tests/baselines/reference/typeGuardOfFormIsType.types +++ b/tests/baselines/reference/typeGuardOfFormIsType.types @@ -80,7 +80,7 @@ num = isC2(c1Orc2) && c1Orc2.p2; // C2 >isC2(c1Orc2) && c1Orc2.p2 : number >isC2(c1Orc2) : boolean >isC2 : (x: any) => x is C2 ->c1Orc2 : C1 | C2 +>c1Orc2 : C2 | C1 >c1Orc2.p2 : number >c1Orc2 : C2 >p2 : number @@ -129,7 +129,7 @@ num = isD1(c2Ord1) && c2Ord1.p3; // D1 >isD1(c2Ord1) && c2Ord1.p3 : number >isD1(c2Ord1) : boolean >isD1 : (x: any) => x is D1 ->c2Ord1 : C2 | D1 +>c2Ord1 : D1 | C2 >c2Ord1.p3 : number >c2Ord1 : D1 >p3 : number diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types index ea169e95413..728d3dc0e38 100644 --- a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types @@ -111,7 +111,7 @@ num = isC2(c1Orc2) && c1Orc2.p2; // C2 >isC2(c1Orc2) && c1Orc2.p2 : number >isC2(c1Orc2) : boolean >isC2 : (x: any) => x is C2 ->c1Orc2 : C1 | C2 +>c1Orc2 : C2 | C1 >c1Orc2.p2 : number >c1Orc2 : C2 >p2 : number @@ -160,7 +160,7 @@ num = isD1(c2Ord1) && c2Ord1.p3; // D1 >isD1(c2Ord1) && c2Ord1.p3 : number >isD1(c2Ord1) : boolean >isD1 : (x: any) => x is D1 ->c2Ord1 : C2 | D1 +>c2Ord1 : D1 | C2 >c2Ord1.p3 : number >c2Ord1 : D1 >p3 : number From db6f5bd8326783e44951caf51a581181e11bd9c0 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Fri, 8 Apr 2016 12:53:19 -0700 Subject: [PATCH 030/110] Rename the `forEachProject` function to something sane --- src/compiler/core.ts | 7 +------ src/server/editorServices.ts | 2 +- src/server/session.ts | 8 ++++---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index df8e3d1bce4..c6f1f9bcbaa 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -94,12 +94,7 @@ namespace ts { export function contains(array: T[], value: T, areEqual?: (a: T, b: T) => boolean): boolean { if (array) { for (const v of array) { - if (areEqual) { - if (areEqual(v, value)) { - return true; - } - } - else if (v === value) { + if (areEqual ? areEqual(v, value) : v === value) { return true; } } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 85285a4f3bd..e3bf97f2736 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -464,7 +464,7 @@ namespace ts.server { return copiedList; } - export function forEachProject(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) { + export function processEachProjectThenConcatSortDeduplicateResults(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) { const result = projects.reduce((previous, current) => concatenate(previous, action(current)), []).sort(comparer); return projects.length > 1 ? deduplicate(result, areEqual) : result; } diff --git a/src/server/session.ts b/src/server/session.ts index db64d7edde2..d81b0ee286e 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -434,7 +434,7 @@ namespace ts.server { }; } - const fileSpans = forEachProject( + const fileSpans = processEachProjectThenConcatSortDeduplicateResults( projects, (project: Project) => { const compilerService = project.compilerService; @@ -511,7 +511,7 @@ namespace ts.server { const nameSpan = nameInfo.textSpan; const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset; const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); - const refs = forEachProject( + const refs = processEachProjectThenConcatSortDeduplicateResults( projects, (project: Project) => { const compilerService = project.compilerService; @@ -872,7 +872,7 @@ namespace ts.server { throw Errors.NoProject; } - const allNavToItems = forEachProject( + const allNavToItems = processEachProjectThenConcatSortDeduplicateResults( projects, (project: Project) => { const compilerService = project.compilerService; @@ -891,7 +891,7 @@ namespace ts.server { start: start, end: end, }; - if (navItem.kindModifiers && (navItem.kindModifiers != "")) { + if (navItem.kindModifiers && (navItem.kindModifiers !== "")) { bakedItem.kindModifiers = navItem.kindModifiers; } if (navItem.matchKind !== "none") { From f13c92f0366acb29c01917bd1ddc18bedf428fda Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Apr 2016 15:08:22 -0700 Subject: [PATCH 031/110] Handle shorthand property assignments --- src/compiler/checker.ts | 13 +++++++++++-- src/compiler/utilities.ts | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2393b236648..918acb410aa 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7358,7 +7358,7 @@ namespace ts { return createArrayType(elementType); } - function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment): Type { + function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type { const objectType = getAssignedType(node.parent); const text = getTextOfPropertyName(node.name); return getTypeOfPropertyOfType(objectType, text) || @@ -7367,6 +7367,15 @@ namespace ts { unknownType; } + function getAssignedTypeOfShorthandPropertyAssignment(node: ShorthandPropertyAssignment): Type { + if (node.objectAssignmentInitializer) { + const defaultType = checkExpressionCached(node.objectAssignmentInitializer); + const assignedType = getAssignedTypeOfPropertyAssignment(node); + return getUnionType([getTypeWithFacts(assignedType, TypeFacts.NEUndefined), defaultType]); + } + return getAssignedTypeOfPropertyAssignment(node); + } + function getAssignedType(node: Expression): Type { const parent = node.parent; switch (parent.kind) { @@ -7383,7 +7392,7 @@ namespace ts { case SyntaxKind.PropertyAssignment: return getAssignedTypeOfPropertyAssignment(parent); case SyntaxKind.ShorthandPropertyAssignment: - break; // !!! TODO + return getAssignedTypeOfShorthandPropertyAssignment(parent); } return unknownType; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 45567538dcd..f6a4b81e6d2 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1329,7 +1329,7 @@ namespace ts { node = parent; continue; } - if (parent.kind === SyntaxKind.PropertyAssignment) { + if (parent.kind === SyntaxKind.PropertyAssignment || parent.kind === SyntaxKind.ShorthandPropertyAssignment) { node = parent.parent; continue; } From b03d087e79f832959b8d764547d8c1fdc4c6cdc6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Apr 2016 15:10:10 -0700 Subject: [PATCH 032/110] Accepting new baselines --- .../reference/assignmentTypeNarrowing.js | 53 ++++++++++ .../reference/assignmentTypeNarrowing.symbols | 64 ++++++++++++ .../reference/assignmentTypeNarrowing.types | 98 +++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 tests/baselines/reference/assignmentTypeNarrowing.js create mode 100644 tests/baselines/reference/assignmentTypeNarrowing.symbols create mode 100644 tests/baselines/reference/assignmentTypeNarrowing.types diff --git a/tests/baselines/reference/assignmentTypeNarrowing.js b/tests/baselines/reference/assignmentTypeNarrowing.js new file mode 100644 index 00000000000..7c10dde65cc --- /dev/null +++ b/tests/baselines/reference/assignmentTypeNarrowing.js @@ -0,0 +1,53 @@ +//// [assignmentTypeNarrowing.ts] +let x: string | number | boolean | RegExp; + +x = ""; +x; // string + +[x] = [true]; +x; // boolean + +[x = ""] = [1]; +x; // string | number + +({x} = {x: true}); +x; // boolean + +({y: x} = {y: 1}); +x; // number + +({x = ""} = {x: true}); +x; // string | boolean + +({y: x = /a/} = {y: 1}); +x; // number | RegExp + +let a: string[]; + +for (x of a) { + x; // string +} + + +//// [assignmentTypeNarrowing.js] +var x; +x = ""; +x; // string +x = [true][0]; +x; // boolean +_a = [1][0], x = _a === void 0 ? "" : _a; +x; // string | number +(_b = { x: true }, x = _b.x, _b); +x; // boolean +(_c = { y: 1 }, x = _c.y, _c); +x; // number +(_d = { x: true }, _e = _d.x, x = _e === void 0 ? "" : _e, _d); +x; // string | boolean +(_f = { y: 1 }, _g = _f.y, x = _g === void 0 ? /a/ : _g, _f); +x; // number | RegExp +var a; +for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { + x = a_1[_i]; + x; // string +} +var _a, _b, _c, _d, _e, _f, _g; diff --git a/tests/baselines/reference/assignmentTypeNarrowing.symbols b/tests/baselines/reference/assignmentTypeNarrowing.symbols new file mode 100644 index 00000000000..7d638d6a76b --- /dev/null +++ b/tests/baselines/reference/assignmentTypeNarrowing.symbols @@ -0,0 +1,64 @@ +=== tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts === +let x: string | number | boolean | RegExp; +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +x = ""; +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +x; // string +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +[x] = [true]; +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +x; // boolean +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +[x = ""] = [1]; +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +x; // string | number +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +({x} = {x: true}); +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 11, 2)) +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 11, 8)) + +x; // boolean +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +({y: x} = {y: 1}); +>y : Symbol(y, Decl(assignmentTypeNarrowing.ts, 14, 2)) +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) +>y : Symbol(y, Decl(assignmentTypeNarrowing.ts, 14, 11)) + +x; // number +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +({x = ""} = {x: true}); +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 17, 2)) +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 17, 13)) + +x; // string | boolean +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +({y: x = /a/} = {y: 1}); +>y : Symbol(y, Decl(assignmentTypeNarrowing.ts, 20, 2)) +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) +>y : Symbol(y, Decl(assignmentTypeNarrowing.ts, 20, 17)) + +x; // number | RegExp +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) + +let a: string[]; +>a : Symbol(a, Decl(assignmentTypeNarrowing.ts, 23, 3)) + +for (x of a) { +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) +>a : Symbol(a, Decl(assignmentTypeNarrowing.ts, 23, 3)) + + x; // string +>x : Symbol(x, Decl(assignmentTypeNarrowing.ts, 0, 3)) +} + diff --git a/tests/baselines/reference/assignmentTypeNarrowing.types b/tests/baselines/reference/assignmentTypeNarrowing.types new file mode 100644 index 00000000000..be99a31501d --- /dev/null +++ b/tests/baselines/reference/assignmentTypeNarrowing.types @@ -0,0 +1,98 @@ +=== tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts === +let x: string | number | boolean | RegExp; +>x : string | number | boolean | RegExp +>RegExp : RegExp + +x = ""; +>x = "" : string +>x : string | number | boolean | RegExp +>"" : string + +x; // string +>x : string + +[x] = [true]; +>[x] = [true] : [boolean] +>[x] : [string | number | boolean | RegExp] +>x : string | number | boolean | RegExp +>[true] : [boolean] +>true : boolean + +x; // boolean +>x : boolean + +[x = ""] = [1]; +>[x = ""] = [1] : [number] +>[x = ""] : [string] +>x = "" : string +>x : string | number | boolean | RegExp +>"" : string +>[1] : [number] +>1 : number + +x; // string | number +>x : string | number + +({x} = {x: true}); +>({x} = {x: true}) : { x: boolean; } +>{x} = {x: true} : { x: boolean; } +>{x} : { x: string | number | boolean | RegExp; } +>x : string | number | boolean | RegExp +>{x: true} : { x: boolean; } +>x : boolean +>true : boolean + +x; // boolean +>x : boolean + +({y: x} = {y: 1}); +>({y: x} = {y: 1}) : { y: number; } +>{y: x} = {y: 1} : { y: number; } +>{y: x} : { y: string | number | boolean | RegExp; } +>y : string | number | boolean | RegExp +>x : string | number | boolean | RegExp +>{y: 1} : { y: number; } +>y : number +>1 : number + +x; // number +>x : number + +({x = ""} = {x: true}); +>({x = ""} = {x: true}) : { x?: boolean; } +>{x = ""} = {x: true} : { x?: boolean; } +>{x = ""} : { x?: string | number | boolean | RegExp; } +>x : string | number | boolean | RegExp +>{x: true} : { x?: boolean; } +>x : boolean +>true : boolean + +x; // string | boolean +>x : string | boolean + +({y: x = /a/} = {y: 1}); +>({y: x = /a/} = {y: 1}) : { y?: number; } +>{y: x = /a/} = {y: 1} : { y?: number; } +>{y: x = /a/} : { y?: RegExp; } +>y : RegExp +>x = /a/ : RegExp +>x : string | number | boolean | RegExp +>/a/ : RegExp +>{y: 1} : { y?: number; } +>y : number +>1 : number + +x; // number | RegExp +>x : number | RegExp + +let a: string[]; +>a : string[] + +for (x of a) { +>x : string | number | boolean | RegExp +>a : string[] + + x; // string +>x : string +} + From 7a321293bf43de3ac4ffbdf1281eb5886b623341 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 9 Apr 2016 16:56:23 -0700 Subject: [PATCH 033/110] Support destructuring declarations in control flow analysis --- src/compiler/checker.ts | 125 ++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 49 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 918acb410aa..e12f65b7291 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7335,45 +7335,52 @@ namespace ts { return firstType ? types ? getUnionType(types, /*noSubtypeReduction*/ true) : firstType : emptyUnionType; } - function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { - const type = checkExpressionCached(node.right); - const parent = node.parent; - if (parent.kind === SyntaxKind.ArrayLiteralExpression || parent.kind === SyntaxKind.PropertyAssignment) { - const assignedType = getAssignedType(node); - return getUnionType([getTypeWithFacts(assignedType, TypeFacts.NEUndefined), type]); + function getTypeWithDefault(type: Type, defaultExpression: Expression) { + if (defaultExpression) { + const defaultType = checkExpressionCached(defaultExpression); + return getUnionType([getTypeWithFacts(type, TypeFacts.NEUndefined), defaultType]); } return type; } - function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { - const arrayLikeType = getAssignedType(node); - const elementType = checkIteratedTypeOrElementType(arrayLikeType, node, /*allowStringInput*/ false); - const propName = "" + indexOf(node.elements, element); - return isTupleLikeType(arrayLikeType) && getTypeOfPropertyOfType(arrayLikeType, propName) || elementType; - } - - function getAssignedTypeOfSpreadElement(node: SpreadElementExpression): Type { - const arrayLikeType = getAssignedType(node.parent); - const elementType = checkIteratedTypeOrElementType(arrayLikeType, node, /*allowStringInput*/ false); - return createArrayType(elementType); - } - - function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type { - const objectType = getAssignedType(node.parent); - const text = getTextOfPropertyName(node.name); - return getTypeOfPropertyOfType(objectType, text) || - isNumericLiteralName(text) && getIndexTypeOfType(objectType, IndexKind.Number) || - getIndexTypeOfType(objectType, IndexKind.String) || + function getTypeOfDestructuredProperty(type: Type, name: Identifier | LiteralExpression | ComputedPropertyName) { + const text = getTextOfPropertyName(name); + return getTypeOfPropertyOfType(type, text) || + isNumericLiteralName(text) && getIndexTypeOfType(type, IndexKind.Number) || + getIndexTypeOfType(type, IndexKind.String) || unknownType; } + function getTypeOfDestructuredArrayElement(type: Type, index: number) { + return isTupleLikeType(type) && getTypeOfPropertyOfType(type, "" + index) || + checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false) || + unknownType; + } + + function getTypeOfDestructuredSpreadElement(type: Type) { + return createArrayType(checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false) || unknownType); + } + + function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { + return node.parent.kind === SyntaxKind.ArrayLiteralExpression || node.parent.kind === SyntaxKind.PropertyAssignment ? + getTypeWithDefault(getAssignedType(node), node.right) : + checkExpressionCached(node.right); + } + + function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { + return getTypeOfDestructuredArrayElement(getAssignedType(node), indexOf(node.elements, element)); + } + + function getAssignedTypeOfSpreadElement(node: SpreadElementExpression): Type { + return getTypeOfDestructuredSpreadElement(getAssignedType(node.parent)); + } + + function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type { + return getTypeOfDestructuredProperty(getAssignedType(node.parent), node.name); + } + function getAssignedTypeOfShorthandPropertyAssignment(node: ShorthandPropertyAssignment): Type { - if (node.objectAssignmentInitializer) { - const defaultType = checkExpressionCached(node.objectAssignmentInitializer); - const assignedType = getAssignedTypeOfPropertyAssignment(node); - return getUnionType([getTypeWithFacts(assignedType, TypeFacts.NEUndefined), defaultType]); - } - return getAssignedTypeOfPropertyAssignment(node); + return getTypeWithDefault(getAssignedTypeOfPropertyAssignment(node), node.objectAssignmentInitializer); } function getAssignedType(node: Expression): Type { @@ -7382,7 +7389,7 @@ namespace ts { case SyntaxKind.ForInStatement: return stringType; case SyntaxKind.ForOfStatement: - return checkRightHandSideOfForOf((parent).expression); + return checkRightHandSideOfForOf((parent).expression) || unknownType; case SyntaxKind.BinaryExpression: return getAssignedTypeOfBinaryExpression(parent); case SyntaxKind.ArrayLiteralExpression: @@ -7397,6 +7404,36 @@ namespace ts { return unknownType; } + function getInitialTypeOfBindingElement(node: BindingElement): Type { + const pattern = node.parent; + const parentType = getInitialType(pattern.parent); + const type = pattern.kind === SyntaxKind.ObjectBindingPattern ? + getTypeOfDestructuredProperty(parentType, node.propertyName || node.name) : + !node.dotDotDotToken ? + getTypeOfDestructuredArrayElement(parentType, indexOf(pattern.elements, node)) : + getTypeOfDestructuredSpreadElement(parentType); + return getTypeWithDefault(type, node.initializer); + } + + function getInitialTypeOfVariableDeclaration(node: VariableDeclaration) { + if (node.initializer) { + return checkExpressionCached(node.initializer); + } + if (node.parent.parent.kind === SyntaxKind.ForInStatement) { + return stringType; + } + if (node.parent.parent.kind === SyntaxKind.ForOfStatement) { + return checkRightHandSideOfForOf((node.parent.parent).expression) || unknownType; + } + return unknownType; + } + + function getInitialType(node: VariableDeclaration | BindingElement) { + return node.kind === SyntaxKind.VariableDeclaration ? + getInitialTypeOfVariableDeclaration(node) : + getInitialTypeOfBindingElement(node); + } + function getNarrowedTypeOfReference(type: Type, reference: Node) { if (!(type.flags & TypeFlags.Narrowable) || !isNarrowableReference(reference)) { return type; @@ -7446,20 +7483,12 @@ namespace ts { } } - function getTypeAtVariableDeclaration(node: VariableDeclaration | BindingElement) { - if (reference.kind === SyntaxKind.Identifier && getResolvedSymbol(reference) === getSymbolOfNode(node)) { - if (node.initializer) { - return getAssignmentReducedType(declaredType, checkExpressionCached(node.initializer)); - } - return declaredType; // !!! TODO - } - return undefined; - } - function getTypeAtFlowAssignment(flow: FlowAssignment) { const node = flow.node; - if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { - return getTypeAtVariableDeclaration(node); + if ((node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) && + reference.kind === SyntaxKind.Identifier && + getResolvedSymbol(reference) === getSymbolOfNode(node)) { + return getAssignmentReducedType(declaredType, getInitialType(node)); } // If the node is not a variable declaration or binding element, it is an identifier // or a dotted name that is the target of an assignment. If we have a match, reduce @@ -14091,23 +14120,21 @@ namespace ts { if (isTypeAny(inputType)) { return inputType; } - if (languageVersion >= ScriptTarget.ES6) { return checkElementTypeOfIterable(inputType, errorNode); } - if (allowStringInput) { return checkElementTypeOfArrayOrString(inputType, errorNode); } - if (isArrayLikeType(inputType)) { const indexType = getIndexTypeOfType(inputType, IndexKind.Number); if (indexType) { return indexType; } } - - error(errorNode, Diagnostics.Type_0_is_not_an_array_type, typeToString(inputType)); + if (errorNode) { + error(errorNode, Diagnostics.Type_0_is_not_an_array_type, typeToString(inputType)); + } return unknownType; } From 6fb9424b8444bcb4a5585aa16ccd997bcf371e0e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 9 Apr 2016 16:57:05 -0700 Subject: [PATCH 034/110] Accepting new baselines --- ...dationDestructuringForArrayBindingPatternDefaultValues.types | 2 +- tests/baselines/reference/stringLiteralTypesAndTuples01.types | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types index 102e784aa91..245328296eb 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types +++ b/tests/baselines/reference/sourceMapValidationDestructuringForArrayBindingPatternDefaultValues.types @@ -595,5 +595,5 @@ for (let [numberA3 = -1, ...robotAInfo] = [2, "trimmer", "trimming"], i = 0; i < >console.log : (msg: any) => void >console : { log(msg: any): void; } >log : (msg: any) => void ->numberA3 : number +>numberA3 : number | string } diff --git a/tests/baselines/reference/stringLiteralTypesAndTuples01.types b/tests/baselines/reference/stringLiteralTypesAndTuples01.types index c874973e3e5..e8b5b37a2dd 100644 --- a/tests/baselines/reference/stringLiteralTypesAndTuples01.types +++ b/tests/baselines/reference/stringLiteralTypesAndTuples01.types @@ -28,7 +28,7 @@ let [im, a, dinosaur]: ["I'm", "a", RexOrRaptor] = ['I\'m', 'a', 't-rex']; rawr(dinosaur); >rawr(dinosaur) : string >rawr : (dino: "t-rex" | "raptor") => string ->dinosaur : "t-rex" | "raptor" +>dinosaur : "t-rex" function rawr(dino: RexOrRaptor) { >rawr : (dino: "t-rex" | "raptor") => string From e45bac813954c72494ecd2cb5672ed51858c3a83 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 9 Apr 2016 17:56:03 -0700 Subject: [PATCH 035/110] Adding test --- .../controlFlowDestructuringDeclaration.js | 113 ++++++++++ ...ontrolFlowDestructuringDeclaration.symbols | 164 +++++++++++++++ .../controlFlowDestructuringDeclaration.types | 196 ++++++++++++++++++ .../controlFlowDestructuringDeclaration.ts | 59 ++++++ 4 files changed, 532 insertions(+) create mode 100644 tests/baselines/reference/controlFlowDestructuringDeclaration.js create mode 100644 tests/baselines/reference/controlFlowDestructuringDeclaration.symbols create mode 100644 tests/baselines/reference/controlFlowDestructuringDeclaration.types create mode 100644 tests/cases/conformance/controlFlow/controlFlowDestructuringDeclaration.ts diff --git a/tests/baselines/reference/controlFlowDestructuringDeclaration.js b/tests/baselines/reference/controlFlowDestructuringDeclaration.js new file mode 100644 index 00000000000..766fb6baeb2 --- /dev/null +++ b/tests/baselines/reference/controlFlowDestructuringDeclaration.js @@ -0,0 +1,113 @@ +//// [controlFlowDestructuringDeclaration.ts] + +function f1() { + let x: string | number = 1; + x; + let y: string | undefined = ""; + y; +} + +function f2() { + let [x]: [string | number] = [1]; + x; + let [y]: [string | undefined] = [""]; + y; + let [z = ""]: [string | undefined] = [undefined]; + z; +} + +function f3() { + let [x]: (string | number)[] = [1]; + x; + let [y]: (string | undefined)[] = [""]; + y; + let [z = ""]: (string | undefined)[] = [undefined]; + z; +} + +function f4() { + let { x }: { x: string | number } = { x: 1 }; + x; + let { y }: { y: string | undefined } = { y: "" }; + y; + let { z = "" }: { z: string | undefined } = { z: undefined }; + z; +} + +function f5() { + let { x }: { x?: string | number } = { x: 1 }; + x; + let { y }: { y?: string | undefined } = { y: "" }; + y; + let { z = "" }: { z?: string | undefined } = { z: undefined }; + z; +} + +function f6() { + let { x }: { x?: string | number } = {}; + x; + let { y }: { y?: string | undefined } = {}; + y; + let { z = "" }: { z?: string | undefined } = {}; + z; +} + +function f7() { + let o: { [x: string]: number } = { x: 1 }; + let { x }: { [x: string]: string | number } = o; + x; +} + + +//// [controlFlowDestructuringDeclaration.js] +function f1() { + var x = 1; + x; + var y = ""; + y; +} +function f2() { + var x = [1][0]; + x; + var y = [""][0]; + y; + var _a = [undefined][0], z = _a === void 0 ? "" : _a; + z; +} +function f3() { + var x = [1][0]; + x; + var y = [""][0]; + y; + var _a = [undefined][0], z = _a === void 0 ? "" : _a; + z; +} +function f4() { + var x = { x: 1 }.x; + x; + var y = { y: "" }.y; + y; + var _a = { z: undefined }.z, z = _a === void 0 ? "" : _a; + z; +} +function f5() { + var x = { x: 1 }.x; + x; + var y = { y: "" }.y; + y; + var _a = { z: undefined }.z, z = _a === void 0 ? "" : _a; + z; +} +function f6() { + var x = {}.x; + x; + var y = {}.y; + y; + var _a = {}.z, z = _a === void 0 ? "" : _a; + z; +} +function f7() { + var o = { x: 1 }; + var x = o.x; + x; +} diff --git a/tests/baselines/reference/controlFlowDestructuringDeclaration.symbols b/tests/baselines/reference/controlFlowDestructuringDeclaration.symbols new file mode 100644 index 00000000000..65f0e497942 --- /dev/null +++ b/tests/baselines/reference/controlFlowDestructuringDeclaration.symbols @@ -0,0 +1,164 @@ +=== tests/cases/conformance/controlFlow/controlFlowDestructuringDeclaration.ts === + +function f1() { +>f1 : Symbol(f1, Decl(controlFlowDestructuringDeclaration.ts, 0, 0)) + + let x: string | number = 1; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 2, 7)) + + x; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 2, 7)) + + let y: string | undefined = ""; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 4, 7)) + + y; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 4, 7)) +} + +function f2() { +>f2 : Symbol(f2, Decl(controlFlowDestructuringDeclaration.ts, 6, 1)) + + let [x]: [string | number] = [1]; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 9, 9)) + + x; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 9, 9)) + + let [y]: [string | undefined] = [""]; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 11, 9)) + + y; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 11, 9)) + + let [z = ""]: [string | undefined] = [undefined]; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 13, 9)) +>undefined : Symbol(undefined) + + z; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 13, 9)) +} + +function f3() { +>f3 : Symbol(f3, Decl(controlFlowDestructuringDeclaration.ts, 15, 1)) + + let [x]: (string | number)[] = [1]; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 18, 9)) + + x; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 18, 9)) + + let [y]: (string | undefined)[] = [""]; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 20, 9)) + + y; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 20, 9)) + + let [z = ""]: (string | undefined)[] = [undefined]; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 22, 9)) +>undefined : Symbol(undefined) + + z; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 22, 9)) +} + +function f4() { +>f4 : Symbol(f4, Decl(controlFlowDestructuringDeclaration.ts, 24, 1)) + + let { x }: { x: string | number } = { x: 1 }; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 27, 9)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 27, 16)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 27, 41)) + + x; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 27, 9)) + + let { y }: { y: string | undefined } = { y: "" }; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 29, 9)) +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 29, 16)) +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 29, 44)) + + y; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 29, 9)) + + let { z = "" }: { z: string | undefined } = { z: undefined }; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 31, 9)) +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 31, 21)) +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 31, 49)) +>undefined : Symbol(undefined) + + z; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 31, 9)) +} + +function f5() { +>f5 : Symbol(f5, Decl(controlFlowDestructuringDeclaration.ts, 33, 1)) + + let { x }: { x?: string | number } = { x: 1 }; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 36, 9)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 36, 16)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 36, 42)) + + x; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 36, 9)) + + let { y }: { y?: string | undefined } = { y: "" }; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 38, 9)) +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 38, 16)) +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 38, 45)) + + y; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 38, 9)) + + let { z = "" }: { z?: string | undefined } = { z: undefined }; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 40, 9)) +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 40, 21)) +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 40, 50)) +>undefined : Symbol(undefined) + + z; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 40, 9)) +} + +function f6() { +>f6 : Symbol(f6, Decl(controlFlowDestructuringDeclaration.ts, 42, 1)) + + let { x }: { x?: string | number } = {}; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 45, 9)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 45, 16)) + + x; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 45, 9)) + + let { y }: { y?: string | undefined } = {}; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 47, 9)) +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 47, 16)) + + y; +>y : Symbol(y, Decl(controlFlowDestructuringDeclaration.ts, 47, 9)) + + let { z = "" }: { z?: string | undefined } = {}; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 49, 9)) +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 49, 21)) + + z; +>z : Symbol(z, Decl(controlFlowDestructuringDeclaration.ts, 49, 9)) +} + +function f7() { +>f7 : Symbol(f7, Decl(controlFlowDestructuringDeclaration.ts, 51, 1)) + + let o: { [x: string]: number } = { x: 1 }; +>o : Symbol(o, Decl(controlFlowDestructuringDeclaration.ts, 54, 7)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 54, 14)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 54, 38)) + + let { x }: { [x: string]: string | number } = o; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 55, 9)) +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 55, 18)) +>o : Symbol(o, Decl(controlFlowDestructuringDeclaration.ts, 54, 7)) + + x; +>x : Symbol(x, Decl(controlFlowDestructuringDeclaration.ts, 55, 9)) +} + diff --git a/tests/baselines/reference/controlFlowDestructuringDeclaration.types b/tests/baselines/reference/controlFlowDestructuringDeclaration.types new file mode 100644 index 00000000000..2e3b1f5647e --- /dev/null +++ b/tests/baselines/reference/controlFlowDestructuringDeclaration.types @@ -0,0 +1,196 @@ +=== tests/cases/conformance/controlFlow/controlFlowDestructuringDeclaration.ts === + +function f1() { +>f1 : () => void + + let x: string | number = 1; +>x : string | number +>1 : number + + x; +>x : number + + let y: string | undefined = ""; +>y : string | undefined +>"" : string + + y; +>y : string +} + +function f2() { +>f2 : () => void + + let [x]: [string | number] = [1]; +>x : string | number +>[1] : [number] +>1 : number + + x; +>x : number + + let [y]: [string | undefined] = [""]; +>y : string | undefined +>[""] : [string] +>"" : string + + y; +>y : string + + let [z = ""]: [string | undefined] = [undefined]; +>z : string +>"" : string +>[undefined] : [undefined] +>undefined : undefined + + z; +>z : string +} + +function f3() { +>f3 : () => void + + let [x]: (string | number)[] = [1]; +>x : string | number +>[1] : number[] +>1 : number + + x; +>x : number + + let [y]: (string | undefined)[] = [""]; +>y : string | undefined +>[""] : string[] +>"" : string + + y; +>y : string + + let [z = ""]: (string | undefined)[] = [undefined]; +>z : string +>"" : string +>[undefined] : undefined[] +>undefined : undefined + + z; +>z : string +} + +function f4() { +>f4 : () => void + + let { x }: { x: string | number } = { x: 1 }; +>x : string | number +>x : string | number +>{ x: 1 } : { x: number; } +>x : number +>1 : number + + x; +>x : number + + let { y }: { y: string | undefined } = { y: "" }; +>y : string | undefined +>y : string | undefined +>{ y: "" } : { y: string; } +>y : string +>"" : string + + y; +>y : string + + let { z = "" }: { z: string | undefined } = { z: undefined }; +>z : string +>"" : string +>z : string | undefined +>{ z: undefined } : { z: undefined; } +>z : undefined +>undefined : undefined + + z; +>z : string +} + +function f5() { +>f5 : () => void + + let { x }: { x?: string | number } = { x: 1 }; +>x : string | number | undefined +>x : string | number | undefined +>{ x: 1 } : { x: number; } +>x : number +>1 : number + + x; +>x : number + + let { y }: { y?: string | undefined } = { y: "" }; +>y : string | undefined +>y : string | undefined +>{ y: "" } : { y: string; } +>y : string +>"" : string + + y; +>y : string + + let { z = "" }: { z?: string | undefined } = { z: undefined }; +>z : string +>"" : string +>z : string | undefined +>{ z: undefined } : { z: undefined; } +>z : undefined +>undefined : undefined + + z; +>z : string +} + +function f6() { +>f6 : () => void + + let { x }: { x?: string | number } = {}; +>x : string | number | undefined +>x : string | number | undefined +>{} : {} + + x; +>x : string | number | undefined + + let { y }: { y?: string | undefined } = {}; +>y : string | undefined +>y : string | undefined +>{} : {} + + y; +>y : string | undefined + + let { z = "" }: { z?: string | undefined } = {}; +>z : string +>"" : string +>z : string | undefined +>{} : {} + + z; +>z : string +} + +function f7() { +>f7 : () => void + + let o: { [x: string]: number } = { x: 1 }; +>o : { [x: string]: number; } +>x : string +>{ x: 1 } : { x: number; } +>x : number +>1 : number + + let { x }: { [x: string]: string | number } = o; +>x : string | number +>x : string +>o : { [x: string]: number; } + + x; +>x : number +} + diff --git a/tests/cases/conformance/controlFlow/controlFlowDestructuringDeclaration.ts b/tests/cases/conformance/controlFlow/controlFlowDestructuringDeclaration.ts new file mode 100644 index 00000000000..fc9c3ffb4d7 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowDestructuringDeclaration.ts @@ -0,0 +1,59 @@ +// @strictNullChecks: true + +function f1() { + let x: string | number = 1; + x; + let y: string | undefined = ""; + y; +} + +function f2() { + let [x]: [string | number] = [1]; + x; + let [y]: [string | undefined] = [""]; + y; + let [z = ""]: [string | undefined] = [undefined]; + z; +} + +function f3() { + let [x]: (string | number)[] = [1]; + x; + let [y]: (string | undefined)[] = [""]; + y; + let [z = ""]: (string | undefined)[] = [undefined]; + z; +} + +function f4() { + let { x }: { x: string | number } = { x: 1 }; + x; + let { y }: { y: string | undefined } = { y: "" }; + y; + let { z = "" }: { z: string | undefined } = { z: undefined }; + z; +} + +function f5() { + let { x }: { x?: string | number } = { x: 1 }; + x; + let { y }: { y?: string | undefined } = { y: "" }; + y; + let { z = "" }: { z?: string | undefined } = { z: undefined }; + z; +} + +function f6() { + let { x }: { x?: string | number } = {}; + x; + let { y }: { y?: string | undefined } = {}; + y; + let { z = "" }: { z?: string | undefined } = {}; + z; +} + +function f7() { + let o: { [x: string]: number } = { x: 1 }; + let { x }: { [x: string]: string | number } = o; + x; +} From 7dfcad65b4fe2a76f009a1563337e0c90390ab70 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 9 Apr 2016 17:56:33 -0700 Subject: [PATCH 036/110] Fixing fourslash tests --- tests/cases/fourslash/completionEntryOnNarrowedType.ts | 4 ++-- tests/cases/fourslash/shims-pp/getCompletionsAtPosition.ts | 4 ++-- tests/cases/fourslash/shims/getCompletionsAtPosition.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cases/fourslash/completionEntryOnNarrowedType.ts b/tests/cases/fourslash/completionEntryOnNarrowedType.ts index 714d3390e76..f81572ccebf 100644 --- a/tests/cases/fourslash/completionEntryOnNarrowedType.ts +++ b/tests/cases/fourslash/completionEntryOnNarrowedType.ts @@ -3,10 +3,10 @@ ////function foo(strOrNum: string | number) { //// /*1*/ //// if (typeof strOrNum === "number") { -//// /*2*/ +//// strOrNum/*2*/; //// } //// else { -//// /*3*/ +//// strOrNum/*3*/; //// } ////} diff --git a/tests/cases/fourslash/shims-pp/getCompletionsAtPosition.ts b/tests/cases/fourslash/shims-pp/getCompletionsAtPosition.ts index 714d3390e76..f81572ccebf 100644 --- a/tests/cases/fourslash/shims-pp/getCompletionsAtPosition.ts +++ b/tests/cases/fourslash/shims-pp/getCompletionsAtPosition.ts @@ -3,10 +3,10 @@ ////function foo(strOrNum: string | number) { //// /*1*/ //// if (typeof strOrNum === "number") { -//// /*2*/ +//// strOrNum/*2*/; //// } //// else { -//// /*3*/ +//// strOrNum/*3*/; //// } ////} diff --git a/tests/cases/fourslash/shims/getCompletionsAtPosition.ts b/tests/cases/fourslash/shims/getCompletionsAtPosition.ts index 714d3390e76..f81572ccebf 100644 --- a/tests/cases/fourslash/shims/getCompletionsAtPosition.ts +++ b/tests/cases/fourslash/shims/getCompletionsAtPosition.ts @@ -3,10 +3,10 @@ ////function foo(strOrNum: string | number) { //// /*1*/ //// if (typeof strOrNum === "number") { -//// /*2*/ +//// strOrNum/*2*/; //// } //// else { -//// /*3*/ +//// strOrNum/*3*/; //// } ////} From 92df0297c80c7bd7509ecf2a503d7f98c9a23431 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 9 Apr 2016 18:31:19 -0700 Subject: [PATCH 037/110] Fixing tests --- .../typeGuards/typeGuardFunctionOfFormThis.ts | 24 +++++++++---------- .../thisPredicateFunctionCompletions03.ts | 24 ------------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThis.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThis.ts index aadbf3cd9c5..12f6687c401 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThis.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionOfFormThis.ts @@ -34,19 +34,19 @@ else if (b.isFollower()) { b.follow(); } -if (((a.isLeader)())) { - a.lead(); -} -else if (((a).isFollower())) { - a.follow(); -} +// if (((a.isLeader)())) { +// a.lead(); +// } +// else if (((a).isFollower())) { +// a.follow(); +// } -if (((a["isLeader"])())) { - a.lead(); -} -else if (((a)["isFollower"]())) { - a.follow(); -} +// if (((a["isLeader"])())) { +// a.lead(); +// } +// else if (((a)["isFollower"]())) { +// a.follow(); +// } var holder2 = {a}; diff --git a/tests/cases/fourslash/thisPredicateFunctionCompletions03.ts b/tests/cases/fourslash/thisPredicateFunctionCompletions03.ts index 3c93a859bf3..4985a1ca561 100644 --- a/tests/cases/fourslash/thisPredicateFunctionCompletions03.ts +++ b/tests/cases/fourslash/thisPredicateFunctionCompletions03.ts @@ -38,20 +38,6 @@ //// b./*8*/; //// } //// -//// if (((a.isLeader)())) { -//// a./*9*/; -//// } -//// else if (((a).isFollower())) { -//// a./*10*/; -//// } -//// -//// if (((a["isLeader"])())) { -//// a./*11*/; -//// } -//// else if (((a)["isFollower"]())) { -//// a./*12*/; -//// } -//// //// let leader/*13*/Status = a.isLeader(); //// function isLeaderGuard(g: RoyalGuard) { //// return g.isLeader(); @@ -68,13 +54,3 @@ goTo.marker("6"); verify.completionListContains("lead"); goTo.marker("8"); verify.completionListContains("follow"); - -goTo.marker("9"); -verify.completionListContains("lead"); -goTo.marker("10"); -verify.completionListContains("follow"); - -goTo.marker("11"); -verify.completionListContains("lead"); -goTo.marker("12"); -verify.completionListContains("follow"); \ No newline at end of file From 32e64640d585d0250293a7198cd2e98866cedd61 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 9 Apr 2016 18:31:32 -0700 Subject: [PATCH 038/110] Accepting new baselines --- .../reference/typeGuardFunctionOfFormThis.js | 48 ++++++------- .../typeGuardFunctionOfFormThis.symbols | 50 ++++---------- .../typeGuardFunctionOfFormThis.types | 68 ++++--------------- 3 files changed, 48 insertions(+), 118 deletions(-) diff --git a/tests/baselines/reference/typeGuardFunctionOfFormThis.js b/tests/baselines/reference/typeGuardFunctionOfFormThis.js index 0d1dceccede..ad85f679e0a 100644 --- a/tests/baselines/reference/typeGuardFunctionOfFormThis.js +++ b/tests/baselines/reference/typeGuardFunctionOfFormThis.js @@ -34,19 +34,19 @@ else if (b.isFollower()) { b.follow(); } -if (((a.isLeader)())) { - a.lead(); -} -else if (((a).isFollower())) { - a.follow(); -} +// if (((a.isLeader)())) { +// a.lead(); +// } +// else if (((a).isFollower())) { +// a.follow(); +// } -if (((a["isLeader"])())) { - a.lead(); -} -else if (((a)["isFollower"]())) { - a.follow(); -} +// if (((a["isLeader"])())) { +// a.lead(); +// } +// else if (((a)["isFollower"]())) { +// a.follow(); +// } var holder2 = {a}; @@ -190,18 +190,18 @@ if (b.isLeader()) { else if (b.isFollower()) { b.follow(); } -if (((a.isLeader)())) { - a.lead(); -} -else if (((a).isFollower())) { - a.follow(); -} -if (((a["isLeader"])())) { - a.lead(); -} -else if (((a)["isFollower"]())) { - a.follow(); -} +// if (((a.isLeader)())) { +// a.lead(); +// } +// else if (((a).isFollower())) { +// a.follow(); +// } +// if (((a["isLeader"])())) { +// a.lead(); +// } +// else if (((a)["isFollower"]())) { +// a.follow(); +// } var holder2 = { a: a }; if (holder2.a.isLeader()) { holder2.a; diff --git a/tests/baselines/reference/typeGuardFunctionOfFormThis.symbols b/tests/baselines/reference/typeGuardFunctionOfFormThis.symbols index 4f08201ba64..3ac972200e2 100644 --- a/tests/baselines/reference/typeGuardFunctionOfFormThis.symbols +++ b/tests/baselines/reference/typeGuardFunctionOfFormThis.symbols @@ -91,45 +91,19 @@ else if (b.isFollower()) { >follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40)) } -if (((a.isLeader)())) { ->a.isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18)) ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->isLeader : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18)) +// if (((a.isLeader)())) { +// a.lead(); +// } +// else if (((a).isFollower())) { +// a.follow(); +// } - a.lead(); ->a.lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36)) ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36)) -} -else if (((a).isFollower())) { ->(a).isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5)) ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->isFollower : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5)) - - a.follow(); ->a.follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40)) ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40)) -} - -if (((a["isLeader"])())) { ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->"isLeader" : Symbol(RoyalGuard.isLeader, Decl(typeGuardFunctionOfFormThis.ts, 0, 18)) - - a.lead(); ->a.lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36)) ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->lead : Symbol(LeadGuard.lead, Decl(typeGuardFunctionOfFormThis.ts, 9, 36)) -} -else if (((a)["isFollower"]())) { ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->"isFollower" : Symbol(RoyalGuard.isFollower, Decl(typeGuardFunctionOfFormThis.ts, 3, 5)) - - a.follow(); ->a.follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40)) ->a : Symbol(a, Decl(typeGuardFunctionOfFormThis.ts, 17, 3)) ->follow : Symbol(FollowerGuard.follow, Decl(typeGuardFunctionOfFormThis.ts, 13, 40)) -} +// if (((a["isLeader"])())) { +// a.lead(); +// } +// else if (((a)["isFollower"]())) { +// a.follow(); +// } var holder2 = {a}; >holder2 : Symbol(holder2, Decl(typeGuardFunctionOfFormThis.ts, 49, 3)) diff --git a/tests/baselines/reference/typeGuardFunctionOfFormThis.types b/tests/baselines/reference/typeGuardFunctionOfFormThis.types index cd0381a94e9..66d1a4b5b11 100644 --- a/tests/baselines/reference/typeGuardFunctionOfFormThis.types +++ b/tests/baselines/reference/typeGuardFunctionOfFormThis.types @@ -102,63 +102,19 @@ else if (b.isFollower()) { >follow : () => void } -if (((a.isLeader)())) { ->((a.isLeader)()) : boolean ->(a.isLeader)() : boolean ->(a.isLeader) : () => this is LeadGuard ->a.isLeader : () => this is LeadGuard ->a : RoyalGuard ->isLeader : () => this is LeadGuard +// if (((a.isLeader)())) { +// a.lead(); +// } +// else if (((a).isFollower())) { +// a.follow(); +// } - a.lead(); ->a.lead() : void ->a.lead : () => void ->a : LeadGuard ->lead : () => void -} -else if (((a).isFollower())) { ->((a).isFollower()) : boolean ->(a).isFollower() : boolean ->(a).isFollower : () => this is FollowerGuard ->(a) : RoyalGuard ->a : RoyalGuard ->isFollower : () => this is FollowerGuard - - a.follow(); ->a.follow() : void ->a.follow : () => void ->a : FollowerGuard ->follow : () => void -} - -if (((a["isLeader"])())) { ->((a["isLeader"])()) : boolean ->(a["isLeader"])() : boolean ->(a["isLeader"]) : () => this is LeadGuard ->a["isLeader"] : () => this is LeadGuard ->a : RoyalGuard ->"isLeader" : string - - a.lead(); ->a.lead() : void ->a.lead : () => void ->a : LeadGuard ->lead : () => void -} -else if (((a)["isFollower"]())) { ->((a)["isFollower"]()) : boolean ->(a)["isFollower"]() : boolean ->(a)["isFollower"] : () => this is FollowerGuard ->(a) : RoyalGuard ->a : RoyalGuard ->"isFollower" : string - - a.follow(); ->a.follow() : void ->a.follow : () => void ->a : FollowerGuard ->follow : () => void -} +// if (((a["isLeader"])())) { +// a.lead(); +// } +// else if (((a)["isFollower"]())) { +// a.follow(); +// } var holder2 = {a}; >holder2 : { a: RoyalGuard; } From 560e768a5b50c99b3dab2a322f929c51f09c3154 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 9 Apr 2016 18:51:22 -0700 Subject: [PATCH 039/110] Fix linting errors --- src/compiler/binder.ts | 2 -- src/compiler/checker.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 39dca4070a7..166064d31bf 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -441,8 +441,6 @@ namespace ts { let savedCurrentFlow: FlowNode; let savedBreakTarget: FlowLabel; let savedContinueTarget: FlowLabel; - let savedTrueTarget: FlowLabel; - let savedFalseTarget: FlowLabel; let savedActiveLabels: ActiveLabel[]; const kind = node.kind; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e12f65b7291..997d2fc2352 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7590,7 +7590,7 @@ namespace ts { assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull : expr.right.kind === SyntaxKind.NullKeyword ? assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : - assumeTrue ? TypeFacts.EQUndefined: TypeFacts.NEUndefined; + assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; return getTypeWithFacts(type, facts); } From 4c250d046f1c2455862a78a3722dfcf7fbbe9e9a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 10 Apr 2016 09:31:02 -0700 Subject: [PATCH 040/110] Accepting new baselines --- .../reference/equalityWithUnionTypes01.types | 16 ++++---- .../reference/typeAssertions.errors.txt | 40 +++++-------------- 2 files changed, 17 insertions(+), 39 deletions(-) diff --git a/tests/baselines/reference/equalityWithUnionTypes01.types b/tests/baselines/reference/equalityWithUnionTypes01.types index 27bf01c048b..61e38030949 100644 --- a/tests/baselines/reference/equalityWithUnionTypes01.types +++ b/tests/baselines/reference/equalityWithUnionTypes01.types @@ -35,36 +35,36 @@ var z: I1 = x; if (y === z || z === y) { >y === z || z === y : boolean >y === z : boolean ->y : number | I2 +>y : I2 >z : I1 >z === y : boolean >z : I1 ->y : number | I2 +>y : I2 } else if (y !== z || z !== y) { >y !== z || z !== y : boolean >y !== z : boolean ->y : number | I2 +>y : I2 >z : I1 >z !== y : boolean >z : I1 ->y : number | I2 +>y : I2 } else if (y == z || z == y) { >y == z || z == y : boolean >y == z : boolean ->y : number | I2 +>y : I2 >z : I1 >z == y : boolean >z : I1 ->y : number | I2 +>y : I2 } else if (y != z || z != y) { >y != z || z != y : boolean >y != z : boolean ->y : number | I2 +>y : I2 >z : I1 >z != y : boolean >z : I1 ->y : number | I2 +>y : I2 } diff --git a/tests/baselines/reference/typeAssertions.errors.txt b/tests/baselines/reference/typeAssertions.errors.txt index 523d22eb956..0468eb23d22 100644 --- a/tests/baselines/reference/typeAssertions.errors.txt +++ b/tests/baselines/reference/typeAssertions.errors.txt @@ -1,24 +1,14 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(5,5): error TS2346: Supplied parameters do not match any signature of call target. -<<<<<<< HEAD -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. - Property 'p' is missing in type 'SomeOther'. -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. -======= +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. Property 'p' is missing in type 'SomeOther'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. ->>>>>>> master +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. Property 'x' is missing in type 'SomeOther'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(37,13): error TS2352: Type 'SomeDerived' cannot be converted to type 'SomeOther'. Property 'q' is missing in type 'SomeDerived'. -<<<<<<< HEAD -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. -======= tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. ->>>>>>> master +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. Property 'q' is missing in type 'SomeBase'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,5): error TS2304: Cannot find name 'numOrStr'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,14): error TS1005: '>' expected. @@ -71,26 +61,18 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err someBase = someBase; someBase = someOther; // Error ~~~~~~~~~~~~~~~~~~~ -<<<<<<< HEAD -!!! error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. - ~~~~~~~~~~~~~~~~~~~ -!!! error TS2352: Neither type 'SomeOther' nor type 'SomeBase' is assignable to the other. -======= !!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. ->>>>>>> master + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. !!! error TS2352: Property 'p' is missing in type 'SomeOther'. someDerived = someDerived; someDerived = someBase; someDerived = someOther; // Error ~~~~~~~~~~~~~~~~~~~~~~ -<<<<<<< HEAD -!!! error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2352: Neither type 'SomeOther' nor type 'SomeDerived' is assignable to the other. -======= !!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. ->>>>>>> master + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. !!! error TS2352: Property 'x' is missing in type 'SomeOther'. someOther = someDerived; // Error @@ -99,13 +81,9 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err !!! error TS2352: Property 'q' is missing in type 'SomeDerived'. someOther = someBase; // Error ~~~~~~~~~~~~~~~~~~~ -<<<<<<< HEAD -!!! error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. - ~~~~~~~~~~~~~~~~~~~ -!!! error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. -======= !!! error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. ->>>>>>> master + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. !!! error TS2352: Property 'q' is missing in type 'SomeBase'. someOther = someOther; From 7c7a1c000c14651894ce8c2fdec2198a5fef7064 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 12 Apr 2016 09:36:53 -0700 Subject: [PATCH 041/110] A few cosmetic changes --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9233765aeb2..6f506ab0bfd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -207,7 +207,7 @@ namespace ts { TypeofEQSymbol = 1 << 3, // typeof x === "symbol" TypeofEQObject = 1 << 4, // typeof x === "object" TypeofEQFunction = 1 << 5, // typeof x === "function" - TypeofEQHostObject = 1 << 6, // typeof x === "xxx" + TypeofEQHostObject = 1 << 6, // typeof x === "xxx" TypeofNEString = 1 << 7, // typeof x !== "string" TypeofNENumber = 1 << 8, // typeof x !== "number" TypeofNEBoolean = 1 << 9, // typeof x !== "boolean" @@ -16328,7 +16328,7 @@ namespace ts { } if (entityName.parent.kind === SyntaxKind.ExportAssignment) { - return resolveEntityName(entityName, + return resolveEntityName(entityName, /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); } From 586ac55fb4cb0f3cc6812e73ee261e2bc72dd9f1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 12 Apr 2016 13:39:54 -0700 Subject: [PATCH 042/110] Fix finishFlow function and rename to finishFlowLabel --- src/compiler/binder.ts | 55 ++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index d72806e2693..35c94a64f50 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -676,16 +676,13 @@ namespace ts { }; } - function finishFlow(flow: FlowNode): FlowNode { - while (flow.kind === FlowKind.Label) { - const antecedents = (flow).antecedents; - if (!antecedents) { - return unreachableFlow; - } - if (antecedents.length > 1) { - break; - } - flow = antecedents[0]; + function finishFlowLabel(flow: FlowLabel): FlowNode { + const antecedents = flow.antecedents; + if (!antecedents) { + return unreachableFlow; + } + if (antecedents.length === 1) { + return antecedents[0]; } return flow; } @@ -760,10 +757,10 @@ namespace ts { addAntecedent(preWhileLabel, currentFlow); currentFlow = preWhileLabel; bindCondition(node.expression, preBodyLabel, postWhileLabel); - currentFlow = finishFlow(preBodyLabel); + currentFlow = finishFlowLabel(preBodyLabel); bindIterativeStatement(node.statement, postWhileLabel, preWhileLabel); addAntecedent(preWhileLabel, currentFlow); - currentFlow = finishFlow(postWhileLabel); + currentFlow = finishFlowLabel(postWhileLabel); } function bindDoStatement(node: DoStatement): void { @@ -774,9 +771,9 @@ namespace ts { currentFlow = preDoLabel; bindIterativeStatement(node.statement, postDoLabel, preConditionLabel); addAntecedent(preConditionLabel, currentFlow); - currentFlow = finishFlow(preConditionLabel); + currentFlow = finishFlowLabel(preConditionLabel); bindCondition(node.expression, preDoLabel, postDoLabel); - currentFlow = finishFlow(postDoLabel); + currentFlow = finishFlowLabel(postDoLabel); } function bindForStatement(node: ForStatement): void { @@ -787,11 +784,11 @@ namespace ts { addAntecedent(preLoopLabel, currentFlow); currentFlow = preLoopLabel; bindCondition(node.condition, preBodyLabel, postLoopLabel); - currentFlow = finishFlow(preBodyLabel); + currentFlow = finishFlowLabel(preBodyLabel); bindIterativeStatement(node.statement, postLoopLabel, preLoopLabel); bind(node.incrementor); addAntecedent(preLoopLabel, currentFlow); - currentFlow = finishFlow(postLoopLabel); + currentFlow = finishFlowLabel(postLoopLabel); } function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void { @@ -807,7 +804,7 @@ namespace ts { } bindIterativeStatement(node.statement, postLoopLabel, preLoopLabel); addAntecedent(preLoopLabel, currentFlow); - currentFlow = finishFlow(postLoopLabel); + currentFlow = finishFlowLabel(postLoopLabel); } function bindIfStatement(node: IfStatement): void { @@ -815,13 +812,13 @@ namespace ts { const elseLabel = createFlowLabel(); const postIfLabel = createFlowLabel(); bindCondition(node.expression, thenLabel, elseLabel); - currentFlow = finishFlow(thenLabel); + currentFlow = finishFlowLabel(thenLabel); bind(node.thenStatement); addAntecedent(postIfLabel, currentFlow); - currentFlow = finishFlow(elseLabel); + currentFlow = finishFlowLabel(elseLabel); bind(node.elseStatement); addAntecedent(postIfLabel, currentFlow); - currentFlow = finishFlow(postIfLabel); + currentFlow = finishFlowLabel(postIfLabel); } function bindReturnOrThrow(node: ReturnStatement | ThrowStatement): void { @@ -880,7 +877,7 @@ namespace ts { currentFlow = preTryFlow; bind(node.finallyBlock); } - currentFlow = finishFlow(postFinallyLabel); + currentFlow = finishFlowLabel(postFinallyLabel); } function bindSwitchStatement(node: SwitchStatement): void { @@ -898,7 +895,7 @@ namespace ts { } currentBreakTarget = saveBreakTarget; preSwitchCaseFlow = savePreSwitchCaseFlow; - currentFlow = finishFlow(postSwitchLabel); + currentFlow = finishFlowLabel(postSwitchLabel); } function bindCaseBlock(node: CaseBlock): void { @@ -913,7 +910,7 @@ namespace ts { const preCaseLabel = createFlowLabel(); addAntecedent(preCaseLabel, preSwitchCaseFlow); addAntecedent(preCaseLabel, currentFlow); - currentFlow = finishFlow(preCaseLabel); + currentFlow = finishFlowLabel(preCaseLabel); } bind(clause); if (currentFlow.kind !== FlowKind.Unreachable && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) { @@ -953,7 +950,7 @@ namespace ts { file.bindDiagnostics.push(createDiagnosticForNode(node.label, Diagnostics.Unused_label)); } addAntecedent(postStatementLabel, currentFlow); - currentFlow = finishFlow(postStatementLabel); + currentFlow = finishFlowLabel(postStatementLabel); } function bindDestructuringTargetFlow(node: Expression) { @@ -999,7 +996,7 @@ namespace ts { else { bindCondition(node.left, trueTarget, preRightLabel); } - currentFlow = finishFlow(preRightLabel); + currentFlow = finishFlowLabel(preRightLabel); bind(node.operatorToken); bindCondition(node.right, trueTarget, falseTarget); } @@ -1024,7 +1021,7 @@ namespace ts { if (isTopLevelLogicalExpression(node)) { const postExpressionLabel = createFlowLabel(); bindLogicalExpression(node, postExpressionLabel, postExpressionLabel); - currentFlow = finishFlow(postExpressionLabel); + currentFlow = finishFlowLabel(postExpressionLabel); } else { bindLogicalExpression(node, currentTrueTarget, currentFalseTarget); @@ -1043,13 +1040,13 @@ namespace ts { const falseLabel = createFlowLabel(); const postExpressionLabel = createFlowLabel(); bindCondition(node.condition, trueLabel, falseLabel); - currentFlow = finishFlow(trueLabel); + currentFlow = finishFlowLabel(trueLabel); bind(node.whenTrue); addAntecedent(postExpressionLabel, currentFlow); - currentFlow = finishFlow(falseLabel); + currentFlow = finishFlowLabel(falseLabel); bind(node.whenFalse); addAntecedent(postExpressionLabel, currentFlow); - currentFlow = finishFlow(postExpressionLabel); + currentFlow = finishFlowLabel(postExpressionLabel); } function bindInitializedVariableFlow(node: VariableDeclaration | BindingElement) { From cd88f1ea323f3aa6dbe0ffe3bd0c153a01a46191 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 12 Apr 2016 13:40:21 -0700 Subject: [PATCH 043/110] Adding regression test --- .../cases/conformance/controlFlow/controlFlowWhileStatement.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts b/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts index 697a867b886..dd31114adf5 100644 --- a/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts +++ b/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts @@ -37,7 +37,9 @@ function e() { let x: string | number; x = ""; while (cond) { + x; // string | number x = 42; + x; // number } x; // string | number } From 472ab7c8aa702683901eab73b9767d5db0e25167 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 12 Apr 2016 13:40:28 -0700 Subject: [PATCH 044/110] Accepting new baselines --- .../reference/controlFlowWhileStatement.js | 4 +++ .../controlFlowWhileStatement.symbols | 34 +++++++++++-------- .../reference/controlFlowWhileStatement.types | 6 ++++ 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/tests/baselines/reference/controlFlowWhileStatement.js b/tests/baselines/reference/controlFlowWhileStatement.js index fc975764ce1..2dfb716f7cc 100644 --- a/tests/baselines/reference/controlFlowWhileStatement.js +++ b/tests/baselines/reference/controlFlowWhileStatement.js @@ -38,7 +38,9 @@ function e() { let x: string | number; x = ""; while (cond) { + x; // string | number x = 42; + x; // number } x; // string | number } @@ -117,7 +119,9 @@ function e() { var x; x = ""; while (cond) { + x; // string | number x = 42; + x; // number } x; // string | number } diff --git a/tests/baselines/reference/controlFlowWhileStatement.symbols b/tests/baselines/reference/controlFlowWhileStatement.symbols index 27e1b533d14..01af3654f3c 100644 --- a/tests/baselines/reference/controlFlowWhileStatement.symbols +++ b/tests/baselines/reference/controlFlowWhileStatement.symbols @@ -98,22 +98,28 @@ function e() { while (cond) { >cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + x; // string | number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) + x = 42; >x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) + + x; // number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) } x; // string | number >x : Symbol(x, Decl(controlFlowWhileStatement.ts, 36, 7)) } function f() { ->f : Symbol(f, Decl(controlFlowWhileStatement.ts, 42, 1)) +>f : Symbol(f, Decl(controlFlowWhileStatement.ts, 44, 1)) let x: string | number | boolean | RegExp | Function; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 46, 7)) >RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) >Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) x = ""; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 46, 7)) while (cond) { >cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) @@ -122,7 +128,7 @@ function f() { >cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) x = 42; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 46, 7)) break; } @@ -130,33 +136,33 @@ function f() { >cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) x = true; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 46, 7)) continue; } x = /a/; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 46, 7)) } x; // string | number | boolean | RegExp ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 44, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 46, 7)) } function g() { ->g : Symbol(g, Decl(controlFlowWhileStatement.ts, 58, 1)) +>g : Symbol(g, Decl(controlFlowWhileStatement.ts, 60, 1)) let x: string | number | boolean | RegExp | Function; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 62, 7)) >RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) >Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) x = ""; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 62, 7)) while (true) { if (cond) { >cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) x = 42; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 62, 7)) break; } @@ -164,14 +170,14 @@ function g() { >cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) x = true; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 62, 7)) continue; } x = /a/; ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 62, 7)) } x; // number ->x : Symbol(x, Decl(controlFlowWhileStatement.ts, 60, 7)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 62, 7)) } diff --git a/tests/baselines/reference/controlFlowWhileStatement.types b/tests/baselines/reference/controlFlowWhileStatement.types index 7c99b152048..3658a20897a 100644 --- a/tests/baselines/reference/controlFlowWhileStatement.types +++ b/tests/baselines/reference/controlFlowWhileStatement.types @@ -117,10 +117,16 @@ function e() { while (cond) { >cond : boolean + x; // string | number +>x : string | number + x = 42; >x = 42 : number >x : string | number >42 : number + + x; // number +>x : number } x; // string | number >x : string | number From 0417592ccb1cb00ebf6d13821f4a4d5b1918b11e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 12 Apr 2016 16:52:57 -0700 Subject: [PATCH 045/110] Include exported name in error message. --- src/compiler/checker.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ef8ff16c1c0..2d846ce8397 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15790,7 +15790,7 @@ namespace ts { const symbol = resolveName(exportedName, exportedName.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); if (symbol && (symbol === undefinedSymbol || isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { - error(exportedName, Diagnostics.Cannot_re_export_name_that_is_not_defined_in_the_module); + error(exportedName, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, exportedName.text); } else { markExportAsReferenced(node); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b331241660c..7e9964ba4c0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1819,7 +1819,7 @@ "category": "Error", "code": 2660 }, - "Cannot re-export name that is not defined in the module.": { + "Cannot export '{0}'. Only local declarations can be exported from a module.": { "category": "Error", "code": 2661 }, From a25c70b47d976cd4c0aef628f88da4aa513c8743 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 12 Apr 2016 17:09:15 -0700 Subject: [PATCH 046/110] Accepted baselines. --- .../exportSpecifierForAGlobal.errors.txt | 4 +- ...ierReferencingOuterDeclaration1.errors.txt | 4 +- ...ierReferencingOuterDeclaration2.errors.txt | 4 +- .../reExportGlobalDeclaration1.errors.txt | 48 +++++++++---------- .../reExportGlobalDeclaration2.errors.txt | 24 +++++----- .../reExportGlobalDeclaration3.errors.txt | 24 +++++----- .../reExportGlobalDeclaration4.errors.txt | 24 +++++----- .../reference/reExportUndefined1.errors.txt | 4 +- 8 files changed, 68 insertions(+), 68 deletions(-) diff --git a/tests/baselines/reference/exportSpecifierForAGlobal.errors.txt b/tests/baselines/reference/exportSpecifierForAGlobal.errors.txt index 6df9c6de1ef..559b9d5fbfe 100644 --- a/tests/baselines/reference/exportSpecifierForAGlobal.errors.txt +++ b/tests/baselines/reference/exportSpecifierForAGlobal.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/b.ts(1,9): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/b.ts(1,9): error TS2661: Cannot export 'X'. Only local declarations can be exported from a module. ==== tests/cases/compiler/a.d.ts (0 errors) ==== @@ -8,7 +8,7 @@ tests/cases/compiler/b.ts(1,9): error TS2661: Cannot re-export name that is not ==== tests/cases/compiler/b.ts (1 errors) ==== export {X}; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'X'. Only local declarations can be exported from a module. export function f() { var x: X; return x; diff --git a/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration1.errors.txt b/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration1.errors.txt index 7eb095b05f0..6ff2e71d26e 100644 --- a/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration1.errors.txt +++ b/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration1.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/exportSpecifierReferencingOuterDeclaration1.ts(3,14): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/exportSpecifierReferencingOuterDeclaration1.ts(3,14): error TS2661: Cannot export 'X'. Only local declarations can be exported from a module. ==== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration1.ts (1 errors) ==== @@ -6,6 +6,6 @@ tests/cases/compiler/exportSpecifierReferencingOuterDeclaration1.ts(3,14): error declare module "m" { export { X }; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'X'. Only local declarations can be exported from a module. export function foo(): X.bar; } \ No newline at end of file diff --git a/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration2.errors.txt b/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration2.errors.txt index 00118010785..83b8366d40c 100644 --- a/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration2.errors.txt +++ b/tests/baselines/reference/exportSpecifierReferencingOuterDeclaration2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts(1,10): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts(1,10): error TS2661: Cannot export 'X'. Only local declarations can be exported from a module. ==== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_A.ts (0 errors) ==== @@ -7,5 +7,5 @@ tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts(1,10): err ==== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts (1 errors) ==== export { X }; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'X'. Only local declarations can be exported from a module. export declare function foo(): X.bar; \ No newline at end of file diff --git a/tests/baselines/reference/reExportGlobalDeclaration1.errors.txt b/tests/baselines/reference/reExportGlobalDeclaration1.errors.txt index 0ebeed05b28..0d83d8b94ee 100644 --- a/tests/baselines/reference/reExportGlobalDeclaration1.errors.txt +++ b/tests/baselines/reference/reExportGlobalDeclaration1.errors.txt @@ -1,15 +1,15 @@ -tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(1,12): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,13): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(4,12): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(5,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(5,12): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(8,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(9,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(10,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(11,9): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot export 'x'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(1,12): error TS2661: Cannot export 'x'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot export 'x1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,13): error TS2661: Cannot export 'x1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot export 'a'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(4,12): error TS2661: Cannot export 'a'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(5,9): error TS2661: Cannot export 'b'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(5,12): error TS2661: Cannot export 'b'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(8,9): error TS2661: Cannot export 'x'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(9,9): error TS2661: Cannot export 'x1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(10,9): error TS2661: Cannot export 'a'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(11,9): error TS2661: Cannot export 'b'. Only local declarations can be exported from a module. ==== tests/cases/compiler/file1.d.ts (0 errors) ==== @@ -21,37 +21,37 @@ tests/cases/compiler/file2.ts(11,9): error TS2661: Cannot re-export name that is ==== tests/cases/compiler/file2.ts (12 errors) ==== export {x, x as y}; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'x'. Only local declarations can be exported from a module. ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'x'. Only local declarations can be exported from a module. export {x1, x1 as y1}; ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'x1'. Only local declarations can be exported from a module. ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'x1'. Only local declarations can be exported from a module. export {a, a as a1}; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'a'. Only local declarations can be exported from a module. ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'a'. Only local declarations can be exported from a module. export {b, b as b1}; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'b'. Only local declarations can be exported from a module. ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'b'. Only local declarations can be exported from a module. export {x as z}; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'x'. Only local declarations can be exported from a module. export {x1 as z1}; ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'x1'. Only local declarations can be exported from a module. export {a as a2}; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'a'. Only local declarations can be exported from a module. export {b as b2}; ~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'b'. Only local declarations can be exported from a module. \ No newline at end of file diff --git a/tests/baselines/reference/reExportGlobalDeclaration2.errors.txt b/tests/baselines/reference/reExportGlobalDeclaration2.errors.txt index 17a3e2ad565..b24a52aff49 100644 --- a/tests/baselines/reference/reExportGlobalDeclaration2.errors.txt +++ b/tests/baselines/reference/reExportGlobalDeclaration2.errors.txt @@ -1,9 +1,9 @@ -tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(1,13): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,13): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(3,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot export 'I1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(1,13): error TS2661: Cannot export 'I1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot export 'I2'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,13): error TS2661: Cannot export 'I2'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(3,9): error TS2661: Cannot export 'I1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot export 'I2'. Only local declarations can be exported from a module. ==== tests/cases/compiler/file1.d.ts (0 errors) ==== @@ -19,17 +19,17 @@ tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot re-export name that is ==== tests/cases/compiler/file2.ts (6 errors) ==== export {I1, I1 as II1}; ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'I1'. Only local declarations can be exported from a module. ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'I1'. Only local declarations can be exported from a module. export {I2, I2 as II2}; ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'I2'. Only local declarations can be exported from a module. ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'I2'. Only local declarations can be exported from a module. export {I1 as III1}; ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'I1'. Only local declarations can be exported from a module. export {I2 as III2}; ~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. \ No newline at end of file +!!! error TS2661: Cannot export 'I2'. Only local declarations can be exported from a module. \ No newline at end of file diff --git a/tests/baselines/reference/reExportGlobalDeclaration3.errors.txt b/tests/baselines/reference/reExportGlobalDeclaration3.errors.txt index d99c184518c..2f469e80491 100644 --- a/tests/baselines/reference/reExportGlobalDeclaration3.errors.txt +++ b/tests/baselines/reference/reExportGlobalDeclaration3.errors.txt @@ -1,9 +1,9 @@ -tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(1,14): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,14): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(3,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot export 'NS1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(1,14): error TS2661: Cannot export 'NS1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot export 'NS2'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,14): error TS2661: Cannot export 'NS2'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(3,9): error TS2661: Cannot export 'NS1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot export 'NS2'. Only local declarations can be exported from a module. ==== tests/cases/compiler/file1.d.ts (0 errors) ==== @@ -19,17 +19,17 @@ tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot re-export name that is ==== tests/cases/compiler/file2.ts (6 errors) ==== export {NS1, NS1 as NNS1}; ~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'NS1'. Only local declarations can be exported from a module. ~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'NS1'. Only local declarations can be exported from a module. export {NS2, NS2 as NNS2}; ~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'NS2'. Only local declarations can be exported from a module. ~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'NS2'. Only local declarations can be exported from a module. export {NS1 as NNNS1}; ~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'NS1'. Only local declarations can be exported from a module. export {NS2 as NNNS2}; ~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. \ No newline at end of file +!!! error TS2661: Cannot export 'NS2'. Only local declarations can be exported from a module. \ No newline at end of file diff --git a/tests/baselines/reference/reExportGlobalDeclaration4.errors.txt b/tests/baselines/reference/reExportGlobalDeclaration4.errors.txt index 5e250a5fc57..a3b58a276ae 100644 --- a/tests/baselines/reference/reExportGlobalDeclaration4.errors.txt +++ b/tests/baselines/reference/reExportGlobalDeclaration4.errors.txt @@ -1,9 +1,9 @@ -tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(1,15): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(2,15): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(3,9): error TS2661: Cannot re-export name that is not defined in the module. -tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/file2.ts(1,9): error TS2661: Cannot export 'Cls1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(1,15): error TS2661: Cannot export 'Cls1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,9): error TS2661: Cannot export 'Cls2'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(2,15): error TS2661: Cannot export 'Cls2'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(3,9): error TS2661: Cannot export 'Cls1'. Only local declarations can be exported from a module. +tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot export 'Cls2'. Only local declarations can be exported from a module. ==== tests/cases/compiler/file1.d.ts (0 errors) ==== @@ -19,17 +19,17 @@ tests/cases/compiler/file2.ts(4,9): error TS2661: Cannot re-export name that is ==== tests/cases/compiler/file2.ts (6 errors) ==== export {Cls1, Cls1 as CCls1}; ~~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'Cls1'. Only local declarations can be exported from a module. ~~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'Cls1'. Only local declarations can be exported from a module. export {Cls2, Cls2 as CCls2}; ~~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'Cls2'. Only local declarations can be exported from a module. ~~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'Cls2'. Only local declarations can be exported from a module. export {Cls1 as CCCls1}; ~~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. +!!! error TS2661: Cannot export 'Cls1'. Only local declarations can be exported from a module. export {Cls2 as CCCls2}; ~~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. \ No newline at end of file +!!! error TS2661: Cannot export 'Cls2'. Only local declarations can be exported from a module. \ No newline at end of file diff --git a/tests/baselines/reference/reExportUndefined1.errors.txt b/tests/baselines/reference/reExportUndefined1.errors.txt index ff3259ae37e..5042b4c4c0c 100644 --- a/tests/baselines/reference/reExportUndefined1.errors.txt +++ b/tests/baselines/reference/reExportUndefined1.errors.txt @@ -1,8 +1,8 @@ -tests/cases/compiler/a.ts(2,10): error TS2661: Cannot re-export name that is not defined in the module. +tests/cases/compiler/a.ts(2,10): error TS2661: Cannot export 'undefined'. Only local declarations can be exported from a module. ==== tests/cases/compiler/a.ts (1 errors) ==== export { undefined }; ~~~~~~~~~ -!!! error TS2661: Cannot re-export name that is not defined in the module. \ No newline at end of file +!!! error TS2661: Cannot export 'undefined'. Only local declarations can be exported from a module. \ No newline at end of file From b689c07820b13b0b47026c7e0d8813398f837bda Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Apr 2016 06:48:55 -0700 Subject: [PATCH 047/110] Improving error reporting as suggested in code review --- src/compiler/checker.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 369be5258ba..ac8c375dc99 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7528,7 +7528,7 @@ namespace ts { function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) { let key: string; - return reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : initialType; + return reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : declaredType; function getTypeAtFlowNode(flow: FlowNode): Type { while (true) { @@ -7548,6 +7548,10 @@ namespace ts { continue; } return getTypeAtFlowLabel(flow); + case FlowKind.Unreachable: + // Unreachable code errors are reported in the binding phase. Here we + // simply return the declared type to reduce follow-on errors. + return declaredType; } // At the top of the flow we have the initial type return initialType; @@ -7909,6 +7913,8 @@ namespace ts { const flowType = getFlowTypeOfReference(node, type, defaultsToDeclaredType ? type : undefinedType); if (strictNullChecks && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) { error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); + // Return the declared type to reduce follow-on errors + return type; } return flowType; } From 1ed987152fc46236cbf71112e6cf244e3e8d190d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Apr 2016 09:30:16 -0700 Subject: [PATCH 048/110] Fix typo --- src/compiler/binder.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 35c94a64f50..6eefd7c6ef9 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -130,7 +130,7 @@ namespace ts { let classifiableNames: Map; const unreachableFlow: FlowNode = { kind: FlowKind.Unreachable }; - const reportedUncreachableFlow: FlowNode = { kind: FlowKind.Unreachable }; + const reportedUnreachableFlow: FlowNode = { kind: FlowKind.Unreachable }; function bindSourceFile(f: SourceFile, opts: CompilerOptions) { file = f; @@ -2067,7 +2067,7 @@ namespace ts { (node.kind === SyntaxKind.EnumDeclaration && (!isConstEnumDeclaration(node) || options.preserveConstEnums)); if (reportError) { - currentFlow = reportedUncreachableFlow; + currentFlow = reportedUnreachableFlow; // unreachable code is reported if // - user has explicitly asked about it AND From e7a4dd4cf5ffb55f55b7b32569a36acc246fcbd7 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 13 Apr 2016 21:16:39 -0700 Subject: [PATCH 049/110] added validation of paths option --- src/compiler/diagnosticMessages.json | 9 ++++++++- src/compiler/program.ts | 17 ++++++++++++++--- .../reference/pathsValidation1.errors.txt | 6 ++++++ tests/baselines/reference/pathsValidation1.js | 5 +++++ .../reference/pathsValidation2.errors.txt | 6 ++++++ tests/baselines/reference/pathsValidation2.js | 5 +++++ tests/cases/compiler/pathsValidation1.ts | 11 +++++++++++ tests/cases/compiler/pathsValidation2.ts | 11 +++++++++++ 8 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/pathsValidation1.errors.txt create mode 100644 tests/baselines/reference/pathsValidation1.js create mode 100644 tests/baselines/reference/pathsValidation2.errors.txt create mode 100644 tests/baselines/reference/pathsValidation2.js create mode 100644 tests/cases/compiler/pathsValidation1.ts create mode 100644 tests/cases/compiler/pathsValidation2.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b331241660c..301130a3084 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2292,7 +2292,14 @@ "category": "Error", "code": 5062 }, - + "Substututions for patterns '{0}' should be an array.": { + "category": "Error", + "code": 5063 + }, + "Substitution '{0}' for pattern '{1}' has incorrect type, expected 'string', got '{2}'.": { + "category": "Error", + "code": 5064 + }, "Concatenate and emit output to single file.": { "category": "Message", "code": 6001 diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 8d0e8b296e1..9d99f2873af 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1985,11 +1985,22 @@ namespace ts { if (!hasZeroOrOneAsteriskCharacter(key)) { programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key)); } - for (const subst of options.paths[key]) { - if (!hasZeroOrOneAsteriskCharacter(subst)) { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key)); + if (isArray(options.paths[key])) { + for (const subst of options.paths[key]) { + const typeOfSubst = typeof subst; + if (typeOfSubst === "string") { + if (!hasZeroOrOneAsteriskCharacter(subst)) { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key)); + } + } + else { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst)); + } } } + else { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substututions_for_patterns_0_should_be_an_array, key)); + } } } diff --git a/tests/baselines/reference/pathsValidation1.errors.txt b/tests/baselines/reference/pathsValidation1.errors.txt new file mode 100644 index 00000000000..8b82f117353 --- /dev/null +++ b/tests/baselines/reference/pathsValidation1.errors.txt @@ -0,0 +1,6 @@ +error TS5063: Substututions for patterns '*' should be an array. + + +!!! error TS5063: Substututions for patterns '*' should be an array. +==== tests/cases/compiler/a.ts (0 errors) ==== + let x = 1; \ No newline at end of file diff --git a/tests/baselines/reference/pathsValidation1.js b/tests/baselines/reference/pathsValidation1.js new file mode 100644 index 00000000000..bfffc647f63 --- /dev/null +++ b/tests/baselines/reference/pathsValidation1.js @@ -0,0 +1,5 @@ +//// [a.ts] +let x = 1; + +//// [a.js] +var x = 1; diff --git a/tests/baselines/reference/pathsValidation2.errors.txt b/tests/baselines/reference/pathsValidation2.errors.txt new file mode 100644 index 00000000000..8956b2fc159 --- /dev/null +++ b/tests/baselines/reference/pathsValidation2.errors.txt @@ -0,0 +1,6 @@ +error TS5064: Substitution '1' for pattern '*' has incorrect type, expected 'string', got 'number'. + + +!!! error TS5064: Substitution '1' for pattern '*' has incorrect type, expected 'string', got 'number'. +==== tests/cases/compiler/a.ts (0 errors) ==== + let x = 1; \ No newline at end of file diff --git a/tests/baselines/reference/pathsValidation2.js b/tests/baselines/reference/pathsValidation2.js new file mode 100644 index 00000000000..bfffc647f63 --- /dev/null +++ b/tests/baselines/reference/pathsValidation2.js @@ -0,0 +1,5 @@ +//// [a.ts] +let x = 1; + +//// [a.js] +var x = 1; diff --git a/tests/cases/compiler/pathsValidation1.ts b/tests/cases/compiler/pathsValidation1.ts new file mode 100644 index 00000000000..45a4409cf03 --- /dev/null +++ b/tests/cases/compiler/pathsValidation1.ts @@ -0,0 +1,11 @@ +// @filename: tsconfig.json +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": "*" + } + } +} +// @filename: a.ts +let x = 1; \ No newline at end of file diff --git a/tests/cases/compiler/pathsValidation2.ts b/tests/cases/compiler/pathsValidation2.ts new file mode 100644 index 00000000000..b15ad4e236a --- /dev/null +++ b/tests/cases/compiler/pathsValidation2.ts @@ -0,0 +1,11 @@ +// @filename: tsconfig.json +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": [1] + } + } +} +// @filename: a.ts +let x = 1; \ No newline at end of file From 54862a27e27a3ebc07800372b92b28041fd0248d Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 13 Apr 2016 21:36:36 -0700 Subject: [PATCH 050/110] fix typo in message --- src/compiler/diagnosticMessages.json | 2 +- src/compiler/program.ts | 2 +- tests/baselines/reference/pathsValidation1.errors.txt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 301130a3084..5dfd7016af5 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2292,7 +2292,7 @@ "category": "Error", "code": 5062 }, - "Substututions for patterns '{0}' should be an array.": { + "Substututions for pattern '{0}' should be an array.": { "category": "Error", "code": 5063 }, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 9d99f2873af..658d6946a39 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1999,7 +1999,7 @@ namespace ts { } } else { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substututions_for_patterns_0_should_be_an_array, key)); + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substututions_for_pattern_0_should_be_an_array, key)); } } } diff --git a/tests/baselines/reference/pathsValidation1.errors.txt b/tests/baselines/reference/pathsValidation1.errors.txt index 8b82f117353..c6193be67ac 100644 --- a/tests/baselines/reference/pathsValidation1.errors.txt +++ b/tests/baselines/reference/pathsValidation1.errors.txt @@ -1,6 +1,6 @@ -error TS5063: Substututions for patterns '*' should be an array. +error TS5063: Substututions for pattern '*' should be an array. -!!! error TS5063: Substututions for patterns '*' should be an array. +!!! error TS5063: Substututions for pattern '*' should be an array. ==== tests/cases/compiler/a.ts (0 errors) ==== let x = 1; \ No newline at end of file From 8c8eaaa2a2a059a2f9941e34b2f6c39270b124a1 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 14 Apr 2016 11:48:35 -0700 Subject: [PATCH 051/110] Check for class expressions when finding related symbols in base types --- src/services/services.ts | 12 ++++++------ .../fourslash/findAllRefsInClassExpression.ts | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsInClassExpression.ts diff --git a/src/services/services.ts b/src/services/services.ts index c7379fd973d..3c1a9cf919e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1888,7 +1888,7 @@ namespace ts { options.isolatedModules = true; - // transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths. + // transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths. options.suppressOutputPathCheck = true; // Filename can be non-ts file. @@ -5672,7 +5672,7 @@ namespace ts { declaration => (declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined); if (importOrExportSpecifier && - // export { a } + // export { a } (!importOrExportSpecifier.propertyName || // export {a as class } where a is location importOrExportSpecifier.propertyName === location)) { @@ -5752,7 +5752,7 @@ namespace ts { return undefined; } - // If symbol is of object binding pattern element without property name we would want to + // If symbol is of object binding pattern element without property name we would want to // look for property too and that could be anywhere if (isObjectBindingPatternElementWithoutPropertyName(symbol)) { return undefined; @@ -6213,7 +6213,7 @@ namespace ts { result = result.concat(typeChecker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name)); } - // If this is symbol of binding element without propertyName declaration in Object binding pattern + // If this is symbol of binding element without propertyName declaration in Object binding pattern // Include the property in the search const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol); if (bindingElementPropertySymbol) { @@ -6267,7 +6267,7 @@ namespace ts { if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { forEach(symbol.getDeclarations(), declaration => { - if (declaration.kind === SyntaxKind.ClassDeclaration) { + if (isClassLike(declaration)) { getPropertySymbolFromTypeReference(getClassExtendsHeritageClauseElement(declaration)); forEach(getClassImplementsHeritageClauseElements(declaration), getPropertySymbolFromTypeReference); } @@ -6329,7 +6329,7 @@ namespace ts { } } - // If the reference location is the binding element and doesn't have property name + // If the reference location is the binding element and doesn't have property name // then include the binding element in the related symbols // let { a } : { a }; const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol); diff --git a/tests/cases/fourslash/findAllRefsInClassExpression.ts b/tests/cases/fourslash/findAllRefsInClassExpression.ts new file mode 100644 index 00000000000..951acdd336c --- /dev/null +++ b/tests/cases/fourslash/findAllRefsInClassExpression.ts @@ -0,0 +1,16 @@ +/// + +////interface I { [|boom|](): void; } +////new class C implements I { +//// [|boom|](){} +////} + +let ranges = test.ranges() +for (let range of ranges) { + goTo.position(range.start); + + verify.referencesCountIs(ranges.length); + for (let expectedReference of ranges) { + verify.referencesAtPositionContains(expectedReference); + } +} \ No newline at end of file From 78177cfc2cce27a731dd635fc25f6d84a94c0171 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 14 Apr 2016 17:16:53 -0700 Subject: [PATCH 052/110] permit global augmentations to introduce new names --- src/compiler/checker.ts | 13 +++---- .../moduleAugmentationGlobal4.errors.txt | 25 ------------- .../moduleAugmentationGlobal4.symbols | 26 ++++++++++++++ .../reference/moduleAugmentationGlobal4.types | 26 ++++++++++++++ .../moduleAugmentationGlobal5.errors.txt | 28 --------------- .../moduleAugmentationGlobal5.symbols | 28 +++++++++++++++ .../reference/moduleAugmentationGlobal5.types | 28 +++++++++++++++ .../newNamesInGlobalAugmentations1.js | 22 ++++++++++++ .../newNamesInGlobalAugmentations1.symbols | 34 ++++++++++++++++++ .../newNamesInGlobalAugmentations1.types | 35 +++++++++++++++++++ .../newNamesInGlobalAugmentations1.ts | 17 +++++++++ 11 files changed, 221 insertions(+), 61 deletions(-) delete mode 100644 tests/baselines/reference/moduleAugmentationGlobal4.errors.txt create mode 100644 tests/baselines/reference/moduleAugmentationGlobal4.symbols create mode 100644 tests/baselines/reference/moduleAugmentationGlobal4.types delete mode 100644 tests/baselines/reference/moduleAugmentationGlobal5.errors.txt create mode 100644 tests/baselines/reference/moduleAugmentationGlobal5.symbols create mode 100644 tests/baselines/reference/moduleAugmentationGlobal5.types create mode 100644 tests/baselines/reference/newNamesInGlobalAugmentations1.js create mode 100644 tests/baselines/reference/newNamesInGlobalAugmentations1.symbols create mode 100644 tests/baselines/reference/newNamesInGlobalAugmentations1.types create mode 100644 tests/cases/compiler/newNamesInGlobalAugmentations1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 187a53b12ef..53c9b066caf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15596,6 +15596,9 @@ namespace ts { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.TypeAliasDeclaration: + if (isGlobalAugmentation) { + return; + } const symbol = getSymbolOfNode(node); if (symbol) { // module augmentations cannot introduce new names on the top level scope of the module @@ -15604,14 +15607,8 @@ namespace ts { // 2. main check - report error if value declaration of the parent symbol is module augmentation) let reportError = !(symbol.flags & SymbolFlags.Merged); if (!reportError) { - if (isGlobalAugmentation) { - // global symbol should not have parent since it is not explicitly exported - reportError = symbol.parent !== undefined; - } - else { - // symbol should not originate in augmentation - reportError = isExternalModuleAugmentation(symbol.parent.declarations[0]); - } + // symbol should not originate in augmentation + reportError = isExternalModuleAugmentation(symbol.parent.declarations[0]); } if (reportError) { error(node, Diagnostics.Module_augmentation_cannot_introduce_new_names_in_the_top_level_scope); diff --git a/tests/baselines/reference/moduleAugmentationGlobal4.errors.txt b/tests/baselines/reference/moduleAugmentationGlobal4.errors.txt deleted file mode 100644 index fd3444f56b1..00000000000 --- a/tests/baselines/reference/moduleAugmentationGlobal4.errors.txt +++ /dev/null @@ -1,25 +0,0 @@ -tests/cases/compiler/f1.ts(3,15): error TS2665: Module augmentation cannot introduce new names in the top level scope. -tests/cases/compiler/f2.ts(3,15): error TS2665: Module augmentation cannot introduce new names in the top level scope. - - -==== tests/cases/compiler/f1.ts (1 errors) ==== - - declare global { - interface Something {x} - ~~~~~~~~~ -!!! error TS2665: Module augmentation cannot introduce new names in the top level scope. - } - export {}; -==== tests/cases/compiler/f2.ts (1 errors) ==== - - declare global { - interface Something {y} - ~~~~~~~~~ -!!! error TS2665: Module augmentation cannot introduce new names in the top level scope. - } - export {}; -==== tests/cases/compiler/f3.ts (0 errors) ==== - import "./f1"; - import "./f2"; - - \ No newline at end of file diff --git a/tests/baselines/reference/moduleAugmentationGlobal4.symbols b/tests/baselines/reference/moduleAugmentationGlobal4.symbols new file mode 100644 index 00000000000..f9cdac3fc2e --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationGlobal4.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/f1.ts === + +declare global { +>global : Symbol(, Decl(f1.ts, 0, 0)) + + interface Something {x} +>Something : Symbol(Something, Decl(f1.ts, 1, 16), Decl(f2.ts, 1, 16)) +>x : Symbol(Something.x, Decl(f1.ts, 2, 25)) +} +export {}; +=== tests/cases/compiler/f2.ts === + +declare global { +>global : Symbol(, Decl(f2.ts, 0, 0)) + + interface Something {y} +>Something : Symbol(Something, Decl(f1.ts, 1, 16), Decl(f2.ts, 1, 16)) +>y : Symbol(Something.y, Decl(f2.ts, 2, 25)) +} +export {}; +=== tests/cases/compiler/f3.ts === +import "./f1"; +No type information for this code.import "./f2"; +No type information for this code. +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/moduleAugmentationGlobal4.types b/tests/baselines/reference/moduleAugmentationGlobal4.types new file mode 100644 index 00000000000..e3e780d69ff --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationGlobal4.types @@ -0,0 +1,26 @@ +=== tests/cases/compiler/f1.ts === + +declare global { +>global : any + + interface Something {x} +>Something : Something +>x : any +} +export {}; +=== tests/cases/compiler/f2.ts === + +declare global { +>global : any + + interface Something {y} +>Something : Something +>y : any +} +export {}; +=== tests/cases/compiler/f3.ts === +import "./f1"; +No type information for this code.import "./f2"; +No type information for this code. +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/moduleAugmentationGlobal5.errors.txt b/tests/baselines/reference/moduleAugmentationGlobal5.errors.txt deleted file mode 100644 index 4f1f9133760..00000000000 --- a/tests/baselines/reference/moduleAugmentationGlobal5.errors.txt +++ /dev/null @@ -1,28 +0,0 @@ -tests/cases/compiler/f1.d.ts(4,19): error TS2665: Module augmentation cannot introduce new names in the top level scope. -tests/cases/compiler/f2.d.ts(3,19): error TS2665: Module augmentation cannot introduce new names in the top level scope. - - -==== tests/cases/compiler/f3.ts (0 errors) ==== - /// - /// - import "A"; - import "B"; - - -==== tests/cases/compiler/f1.d.ts (1 errors) ==== - - declare module "A" { - global { - interface Something {x} - ~~~~~~~~~ -!!! error TS2665: Module augmentation cannot introduce new names in the top level scope. - } - } -==== tests/cases/compiler/f2.d.ts (1 errors) ==== - declare module "B" { - global { - interface Something {y} - ~~~~~~~~~ -!!! error TS2665: Module augmentation cannot introduce new names in the top level scope. - } - } \ No newline at end of file diff --git a/tests/baselines/reference/moduleAugmentationGlobal5.symbols b/tests/baselines/reference/moduleAugmentationGlobal5.symbols new file mode 100644 index 00000000000..27548b05ef2 --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationGlobal5.symbols @@ -0,0 +1,28 @@ +=== tests/cases/compiler/f3.ts === +/// +No type information for this code./// +No type information for this code.import "A"; +No type information for this code.import "B"; +No type information for this code. +No type information for this code. +No type information for this code.=== tests/cases/compiler/f1.d.ts === + +declare module "A" { + global { +>global : Symbol(, Decl(f1.d.ts, 1, 20)) + + interface Something {x} +>Something : Symbol(Something, Decl(f1.d.ts, 2, 12), Decl(f2.d.ts, 1, 12)) +>x : Symbol(Something.x, Decl(f1.d.ts, 3, 29)) + } +} +=== tests/cases/compiler/f2.d.ts === +declare module "B" { + global { +>global : Symbol(, Decl(f2.d.ts, 0, 20)) + + interface Something {y} +>Something : Symbol(Something, Decl(f1.d.ts, 2, 12), Decl(f2.d.ts, 1, 12)) +>y : Symbol(Something.y, Decl(f2.d.ts, 2, 29)) + } +} diff --git a/tests/baselines/reference/moduleAugmentationGlobal5.types b/tests/baselines/reference/moduleAugmentationGlobal5.types new file mode 100644 index 00000000000..b2e6139eb26 --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationGlobal5.types @@ -0,0 +1,28 @@ +=== tests/cases/compiler/f3.ts === +/// +No type information for this code./// +No type information for this code.import "A"; +No type information for this code.import "B"; +No type information for this code. +No type information for this code. +No type information for this code.=== tests/cases/compiler/f1.d.ts === + +declare module "A" { + global { +>global : any + + interface Something {x} +>Something : Something +>x : any + } +} +=== tests/cases/compiler/f2.d.ts === +declare module "B" { + global { +>global : any + + interface Something {y} +>Something : Something +>y : any + } +} diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.js b/tests/baselines/reference/newNamesInGlobalAugmentations1.js new file mode 100644 index 00000000000..5dc04f2f4aa --- /dev/null +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.js @@ -0,0 +1,22 @@ +//// [tests/cases/compiler/newNamesInGlobalAugmentations1.ts] //// + +//// [f1.d.ts] + +export {}; + +declare global { + interface SymbolConstructor { + observable: symbol; + } + class Cls {x} + let [a, b]: number[]; +} + +//// [main.ts] + +Symbol.observable; +new Cls().x + +//// [main.js] +Symbol.observable; +new Cls().x; diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols b/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols new file mode 100644 index 00000000000..be8ec6aa14d --- /dev/null +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols @@ -0,0 +1,34 @@ +=== tests/cases/compiler/f1.d.ts === + +export {}; + +declare global { +>global : Symbol(, Decl(f1.d.ts, 1, 10)) + + interface SymbolConstructor { +>SymbolConstructor : Symbol(SymbolConstructor, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(f1.d.ts, 3, 16)) + + observable: symbol; +>observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 4, 33)) + } + class Cls {x} +>Cls : Symbol(Cls, Decl(f1.d.ts, 6, 5)) +>x : Symbol(Cls.x, Decl(f1.d.ts, 7, 15)) + + let [a, b]: number[]; +>a : Symbol(a, Decl(f1.d.ts, 8, 9)) +>b : Symbol(b, Decl(f1.d.ts, 8, 11)) +} + +=== tests/cases/compiler/main.ts === + +Symbol.observable; +>Symbol.observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 4, 33)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) +>observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 4, 33)) + +new Cls().x +>new Cls().x : Symbol(Cls.x, Decl(f1.d.ts, 7, 15)) +>Cls : Symbol(Cls, Decl(f1.d.ts, 6, 5)) +>x : Symbol(Cls.x, Decl(f1.d.ts, 7, 15)) + diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.types b/tests/baselines/reference/newNamesInGlobalAugmentations1.types new file mode 100644 index 00000000000..8d5baf19d08 --- /dev/null +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.types @@ -0,0 +1,35 @@ +=== tests/cases/compiler/f1.d.ts === + +export {}; + +declare global { +>global : any + + interface SymbolConstructor { +>SymbolConstructor : SymbolConstructor + + observable: symbol; +>observable : symbol + } + class Cls {x} +>Cls : Cls +>x : any + + let [a, b]: number[]; +>a : number +>b : number +} + +=== tests/cases/compiler/main.ts === + +Symbol.observable; +>Symbol.observable : symbol +>Symbol : SymbolConstructor +>observable : symbol + +new Cls().x +>new Cls().x : any +>new Cls() : Cls +>Cls : typeof Cls +>x : any + diff --git a/tests/cases/compiler/newNamesInGlobalAugmentations1.ts b/tests/cases/compiler/newNamesInGlobalAugmentations1.ts new file mode 100644 index 00000000000..78cd1ec5c13 --- /dev/null +++ b/tests/cases/compiler/newNamesInGlobalAugmentations1.ts @@ -0,0 +1,17 @@ +// @target: es6 + +// @filename: f1.d.ts +export {}; + +declare global { + interface SymbolConstructor { + observable: symbol; + } + class Cls {x} + let [a, b]: number[]; +} + +// @filename: main.ts + +Symbol.observable; +new Cls().x \ No newline at end of file From 0f323ea74a99e4a07525ff55ce21c76163769ccf Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 14 Apr 2016 17:57:17 -0700 Subject: [PATCH 053/110] allow top level 'import x = identifier | qname' in module augmentations --- src/compiler/binder.ts | 2 +- src/compiler/checker.ts | 4 +- .../newNamesInGlobalAugmentations1.js | 8 +++- .../newNamesInGlobalAugmentations1.symbols | 43 +++++++++++++------ .../newNamesInGlobalAugmentations1.types | 21 +++++++++ .../newNamesInGlobalAugmentations1.ts | 7 ++- 6 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9311aa7cc26..0d71abcf123 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -355,7 +355,7 @@ namespace ts { function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { const hasExportModifier = getCombinedNodeFlags(node) & NodeFlags.Export; if (symbolFlags & SymbolFlags.Alias) { - if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier)) { + if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && (hasExportModifier || container.flags & NodeFlags.ExportContext))) { return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes); } else { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 53c9b066caf..3690c24e19b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15572,7 +15572,9 @@ namespace ts { break; case SyntaxKind.ImportEqualsDeclaration: if ((node).moduleReference.kind !== SyntaxKind.StringLiteral) { - error((node).name, Diagnostics.Module_augmentation_cannot_introduce_new_names_in_the_top_level_scope); + if (!isGlobalAugmentation) { + error((node).name, Diagnostics.Module_augmentation_cannot_introduce_new_names_in_the_top_level_scope); + } break; } // fallthrough diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.js b/tests/baselines/reference/newNamesInGlobalAugmentations1.js index 5dc04f2f4aa..053fe46fd42 100644 --- a/tests/baselines/reference/newNamesInGlobalAugmentations1.js +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.js @@ -4,19 +4,25 @@ export {}; +declare module M.M1 { + export let x: number; +} declare global { interface SymbolConstructor { observable: symbol; } class Cls {x} let [a, b]: number[]; + import X = M.M1.x; } //// [main.ts] Symbol.observable; -new Cls().x +new Cls().x +let c = a + b + X; //// [main.js] Symbol.observable; new Cls().x; +let c = a + b + X; diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols b/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols index be8ec6aa14d..eab27b632eb 100644 --- a/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols @@ -2,33 +2,52 @@ export {}; +declare module M.M1 { +>M : Symbol(M, Decl(f1.d.ts, 1, 10)) +>M1 : Symbol(M1, Decl(f1.d.ts, 3, 17)) + + export let x: number; +>x : Symbol(x, Decl(f1.d.ts, 4, 14)) +} declare global { ->global : Symbol(, Decl(f1.d.ts, 1, 10)) +>global : Symbol(, Decl(f1.d.ts, 5, 1)) interface SymbolConstructor { ->SymbolConstructor : Symbol(SymbolConstructor, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(f1.d.ts, 3, 16)) +>SymbolConstructor : Symbol(SymbolConstructor, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(f1.d.ts, 6, 16)) observable: symbol; ->observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 4, 33)) +>observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 7, 33)) } class Cls {x} ->Cls : Symbol(Cls, Decl(f1.d.ts, 6, 5)) ->x : Symbol(Cls.x, Decl(f1.d.ts, 7, 15)) +>Cls : Symbol(Cls, Decl(f1.d.ts, 9, 5)) +>x : Symbol(Cls.x, Decl(f1.d.ts, 10, 15)) let [a, b]: number[]; ->a : Symbol(a, Decl(f1.d.ts, 8, 9)) ->b : Symbol(b, Decl(f1.d.ts, 8, 11)) +>a : Symbol(a, Decl(f1.d.ts, 11, 9)) +>b : Symbol(b, Decl(f1.d.ts, 11, 11)) + + import X = M.M1.x; +>X : Symbol(X, Decl(f1.d.ts, 11, 25)) +>M : Symbol(M, Decl(f1.d.ts, 1, 10)) +>M1 : Symbol(M.M1, Decl(f1.d.ts, 3, 17)) +>x : Symbol(X, Decl(f1.d.ts, 4, 14)) } === tests/cases/compiler/main.ts === Symbol.observable; ->Symbol.observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 4, 33)) +>Symbol.observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 7, 33)) >Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) ->observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 4, 33)) +>observable : Symbol(SymbolConstructor.observable, Decl(f1.d.ts, 7, 33)) new Cls().x ->new Cls().x : Symbol(Cls.x, Decl(f1.d.ts, 7, 15)) ->Cls : Symbol(Cls, Decl(f1.d.ts, 6, 5)) ->x : Symbol(Cls.x, Decl(f1.d.ts, 7, 15)) +>new Cls().x : Symbol(Cls.x, Decl(f1.d.ts, 10, 15)) +>Cls : Symbol(Cls, Decl(f1.d.ts, 9, 5)) +>x : Symbol(Cls.x, Decl(f1.d.ts, 10, 15)) + +let c = a + b + X; +>c : Symbol(c, Decl(main.ts, 3, 3)) +>a : Symbol(a, Decl(f1.d.ts, 11, 9)) +>b : Symbol(b, Decl(f1.d.ts, 11, 11)) +>X : Symbol(X, Decl(f1.d.ts, 11, 25)) diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.types b/tests/baselines/reference/newNamesInGlobalAugmentations1.types index 8d5baf19d08..e1331709d2f 100644 --- a/tests/baselines/reference/newNamesInGlobalAugmentations1.types +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.types @@ -2,6 +2,13 @@ export {}; +declare module M.M1 { +>M : typeof M +>M1 : typeof M1 + + export let x: number; +>x : number +} declare global { >global : any @@ -18,6 +25,12 @@ declare global { let [a, b]: number[]; >a : number >b : number + + import X = M.M1.x; +>X : number +>M : typeof M +>M1 : typeof M.M1 +>x : number } === tests/cases/compiler/main.ts === @@ -33,3 +46,11 @@ new Cls().x >Cls : typeof Cls >x : any +let c = a + b + X; +>c : number +>a + b + X : number +>a + b : number +>a : number +>b : number +>X : number + diff --git a/tests/cases/compiler/newNamesInGlobalAugmentations1.ts b/tests/cases/compiler/newNamesInGlobalAugmentations1.ts index 78cd1ec5c13..22102353250 100644 --- a/tests/cases/compiler/newNamesInGlobalAugmentations1.ts +++ b/tests/cases/compiler/newNamesInGlobalAugmentations1.ts @@ -3,15 +3,20 @@ // @filename: f1.d.ts export {}; +declare module M.M1 { + export let x: number; +} declare global { interface SymbolConstructor { observable: symbol; } class Cls {x} let [a, b]: number[]; + import X = M.M1.x; } // @filename: main.ts Symbol.observable; -new Cls().x \ No newline at end of file +new Cls().x +let c = a + b + X; \ No newline at end of file From 6f3f690a8d7409db87ef4a5ab322f83f305ce26c Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 15 Apr 2016 11:31:26 -0700 Subject: [PATCH 054/110] revert back fix for implicit exports of imports --- src/compiler/binder.ts | 2 +- tests/baselines/reference/newNamesInGlobalAugmentations1.js | 2 +- .../baselines/reference/newNamesInGlobalAugmentations1.symbols | 2 +- tests/baselines/reference/newNamesInGlobalAugmentations1.types | 2 +- tests/cases/compiler/newNamesInGlobalAugmentations1.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 0d71abcf123..9311aa7cc26 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -355,7 +355,7 @@ namespace ts { function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { const hasExportModifier = getCombinedNodeFlags(node) & NodeFlags.Export; if (symbolFlags & SymbolFlags.Alias) { - if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && (hasExportModifier || container.flags & NodeFlags.ExportContext))) { + if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier)) { return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes); } else { diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.js b/tests/baselines/reference/newNamesInGlobalAugmentations1.js index 053fe46fd42..0400f4c3751 100644 --- a/tests/baselines/reference/newNamesInGlobalAugmentations1.js +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.js @@ -13,7 +13,7 @@ declare global { } class Cls {x} let [a, b]: number[]; - import X = M.M1.x; + export import X = M.M1.x; } //// [main.ts] diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols b/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols index eab27b632eb..6215132dd00 100644 --- a/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.symbols @@ -26,7 +26,7 @@ declare global { >a : Symbol(a, Decl(f1.d.ts, 11, 9)) >b : Symbol(b, Decl(f1.d.ts, 11, 11)) - import X = M.M1.x; + export import X = M.M1.x; >X : Symbol(X, Decl(f1.d.ts, 11, 25)) >M : Symbol(M, Decl(f1.d.ts, 1, 10)) >M1 : Symbol(M.M1, Decl(f1.d.ts, 3, 17)) diff --git a/tests/baselines/reference/newNamesInGlobalAugmentations1.types b/tests/baselines/reference/newNamesInGlobalAugmentations1.types index e1331709d2f..a9b879fb4c5 100644 --- a/tests/baselines/reference/newNamesInGlobalAugmentations1.types +++ b/tests/baselines/reference/newNamesInGlobalAugmentations1.types @@ -26,7 +26,7 @@ declare global { >a : number >b : number - import X = M.M1.x; + export import X = M.M1.x; >X : number >M : typeof M >M1 : typeof M.M1 diff --git a/tests/cases/compiler/newNamesInGlobalAugmentations1.ts b/tests/cases/compiler/newNamesInGlobalAugmentations1.ts index 22102353250..73ed4e5e2e8 100644 --- a/tests/cases/compiler/newNamesInGlobalAugmentations1.ts +++ b/tests/cases/compiler/newNamesInGlobalAugmentations1.ts @@ -12,7 +12,7 @@ declare global { } class Cls {x} let [a, b]: number[]; - import X = M.M1.x; + export import X = M.M1.x; } // @filename: main.ts From 96deb553d579422fa1a30acfcba0b1f694c2a280 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Fri, 15 Apr 2016 11:38:42 -0700 Subject: [PATCH 055/110] Script side implementation for Brace Completion. (#7587) * Script side implementation for Brace Completion. This needs updated Visual Studio components to work. * Changed CharacterCodes to number, to keep the API simple * CR feedback * CR feedback and more JSX tests * Swapped 2 comments * typo --- src/harness/fourslash.ts | 53 +++++++++++++++---- src/harness/harnessLanguageService.ts | 3 ++ src/server/client.ts | 4 ++ src/services/services.ts | 33 ++++++++++++ src/services/shims.ts | 14 +++++ src/services/utilities.ts | 44 ++++++++++++++- .../commentBraceCompletionPosition.ts | 23 ++++++++ tests/cases/fourslash/fourslash.ts | 2 + .../fourslash/jsxBraceCompletionPosition.ts | 47 ++++++++++++++++ .../stringBraceCompletionPosition.ts | 16 ++++++ .../stringTemplateBraceCompletionPosition.ts | 16 ++++++ .../fourslash/validBraceCompletionPosition.ts | 23 ++++++++ 12 files changed, 267 insertions(+), 11 deletions(-) create mode 100644 tests/cases/fourslash/commentBraceCompletionPosition.ts create mode 100644 tests/cases/fourslash/jsxBraceCompletionPosition.ts create mode 100644 tests/cases/fourslash/stringBraceCompletionPosition.ts create mode 100644 tests/cases/fourslash/stringTemplateBraceCompletionPosition.ts create mode 100644 tests/cases/fourslash/validBraceCompletionPosition.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 48b79017f8d..6c85d8bcfc0 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -655,7 +655,7 @@ namespace FourSlash { this.assertItemInCompletionList(completions.entries, symbol, text, documentation, kind); } else { - this.raiseError(`No completions at position '${ this.currentCaretPosition }' when looking for '${ symbol }'.`); + this.raiseError(`No completions at position '${this.currentCaretPosition}' when looking for '${symbol}'.`); } } @@ -1758,13 +1758,13 @@ namespace FourSlash { const actual = (this.languageService).getProjectInfo( this.activeFile.fileName, /* needFileNameList */ true - ); + ); assert.equal( expected.join(","), - actual.fileNames.map( file => { + actual.fileNames.map(file => { return file.replace(this.basePath + "/", ""); - }).join(",") - ); + }).join(",") + ); } } @@ -1850,6 +1850,37 @@ namespace FourSlash { }); } + public verifyBraceCompletionAtPostion(negative: boolean, openingBrace: string) { + + const openBraceMap: ts.Map = { + "(": ts.CharacterCodes.openParen, + "{": ts.CharacterCodes.openBrace, + "[": ts.CharacterCodes.openBracket, + "'": ts.CharacterCodes.singleQuote, + '"': ts.CharacterCodes.doubleQuote, + "`": ts.CharacterCodes.backtick, + "<": ts.CharacterCodes.lessThan + }; + + const charCode = openBraceMap[openingBrace]; + + if (!charCode) { + this.raiseError(`Invalid openingBrace '${openingBrace}' specified.`); + } + + const position = this.currentCaretPosition; + + const validBraceCompletion = this.languageService.isValidBraceCompletionAtPostion(this.activeFile.fileName, position, charCode); + + if (!negative && !validBraceCompletion) { + this.raiseError(`${position} is not a valid brace completion position for ${openingBrace}`); + } + + if (negative && validBraceCompletion) { + this.raiseError(`${position} is a valid brace completion position for ${openingBrace}`); + } + } + public verifyMatchingBracePosition(bracePosition: number, expectedMatchPosition: number) { const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition); @@ -2239,7 +2270,7 @@ namespace FourSlash { }; const host = Harness.Compiler.createCompilerHost( - [ fourslashFile, testFile ], + [fourslashFile, testFile], (fn, contents) => result = contents, ts.ScriptTarget.Latest, Harness.IO.useCaseSensitiveFileNames(), @@ -2264,7 +2295,7 @@ namespace FourSlash { function runCode(code: string, state: TestState): void { // Compile and execute the test const wrappedCode = -`(function(test, goTo, verify, edit, debug, format, cancellation, classification, verifyOperationIsCancelled) { + `(function(test, goTo, verify, edit, debug, format, cancellation, classification, verifyOperationIsCancelled) { ${code} })`; try { @@ -2378,7 +2409,7 @@ ${code} } } } - // TODO: should be '==='? + // TODO: should be '==='? } else if (line == "" || lineLength === 0) { // Previously blank lines between fourslash content caused it to be considered as 2 files, @@ -2870,6 +2901,10 @@ namespace FourSlashInterface { public verifyDefinitionsName(name: string, containerName: string) { this.state.verifyDefinitionsName(this.negative, name, containerName); } + + public isValidBraceCompletionAtPostion(openingBrace: string) { + this.state.verifyBraceCompletionAtPostion(this.negative, openingBrace); + } } export class Verify extends VerifyNegatable { @@ -3088,7 +3123,7 @@ namespace FourSlashInterface { this.state.getSemanticDiagnostics(expected); } - public ProjectInfo(expected: string []) { + public ProjectInfo(expected: string[]) { this.state.verifyProjectInfo(expected); } } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index b27d746390b..7e0be67f5a4 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -437,6 +437,9 @@ namespace Harness.LanguageService { getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion { return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position)); } + isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean { + return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPostion(fileName, position, openingBrace)); + } getEmitOutput(fileName: string): ts.EmitOutput { return unwrapJSONCallResult(this.shim.getEmitOutput(fileName)); } diff --git a/src/server/client.ts b/src/server/client.ts index 957d36e4a3a..e8122b39055 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -568,6 +568,10 @@ namespace ts.server { throw new Error("Not Implemented Yet."); } + isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean { + throw new Error("Not Implemented Yet."); + } + getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[] { var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.FileLocationRequestArgs = { diff --git a/src/services/services.ts b/src/services/services.ts index 3c1a9cf919e..d08061664bf 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1113,6 +1113,8 @@ namespace ts { getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion; + isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean; + getEmitOutput(fileName: string): EmitOutput; getProgram(): Program; @@ -7446,6 +7448,36 @@ namespace ts { return { newText: result, caretOffset: preamble.length }; } + function isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean { + + // '<' is currently not supported, figuring out if we're in a Generic Type vs. a comparison is too + // expensive to do during typing scenarios + // i.e. whether we're dealing with: + // var x = new foo<| ( with class foo{} ) + // or + // var y = 3 <| + if (openingBrace === CharacterCodes.lessThan) { + return false; + } + + const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + + // Check if in a context where we don't want to perform any insertion + if (isInString(sourceFile, position) || isInComment(sourceFile, position)) { + return false; + } + + if (isInsideJsxElementOrAttribute(sourceFile, position)) { + return openingBrace === CharacterCodes.openBrace; + } + + if (isInTemplateString(sourceFile, position)) { + return false; + } + + return true; + } + function getParametersForJsDocOwningNode(commentOwner: Node): ParameterDeclaration[] { if (isFunctionLike(commentOwner)) { return commentOwner.parameters; @@ -7740,6 +7772,7 @@ namespace ts { getFormattingEditsForDocument, getFormattingEditsAfterKeystroke, getDocCommentTemplateAtPosition, + isValidBraceCompletionAtPostion, getEmitOutput, getNonBoundSourceFile, getProgram diff --git a/src/services/shims.ts b/src/services/shims.ts index 77a9611ead1..b849407ebab 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -221,6 +221,13 @@ namespace ts { */ getDocCommentTemplateAtPosition(fileName: string, position: number): string; + /** + * Returns JSON-encoded boolean to indicate whether we should support brace location + * at the current position. + * E.g. we don't want brace completion inside string-literals, comments, etc. + */ + isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): string; + getEmitOutput(fileName: string): string; } @@ -733,6 +740,13 @@ namespace ts { ); } + public isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): string { + return this.forwardJSONCall( + `isValidBraceCompletionAtPostion('${fileName}', ${position}, ${openingBrace})`, + () => this.languageService.isValidBraceCompletionAtPostion(fileName, position, openingBrace) + ); + } + /// GET SMART INDENT public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string { return this.forwardJSONCall( diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 4d29cd99e12..6bc5e5c03e6 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -403,13 +403,53 @@ namespace ts { export function isInString(sourceFile: SourceFile, position: number) { let token = getTokenAtPosition(sourceFile, position); - return token && (token.kind === SyntaxKind.StringLiteral || token.kind === SyntaxKind.StringLiteralType) && position > token.getStart(); + return token && (token.kind === SyntaxKind.StringLiteral || token.kind === SyntaxKind.StringLiteralType) && position > token.getStart(sourceFile); } export function isInComment(sourceFile: SourceFile, position: number) { return isInCommentHelper(sourceFile, position, /*predicate*/ undefined); } + /** + * returns true if the position is in between the open and close elements of an JSX expression. + */ + export function isInsideJsxElementOrAttribute(sourceFile: SourceFile, position: number) { + let token = getTokenAtPosition(sourceFile, position); + + if (!token) { + return false; + } + + //
Hello |
+ if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxText) { + return true; + } + + //
{ |
or
+ if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxExpression) { + return true; + } + + //
{ + // | + // } < /div> + if (token && token.kind === SyntaxKind.CloseBraceToken && token.parent.kind === SyntaxKind.JsxExpression) { + return true; + } + + //
|
+ if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxClosingElement) { + return true; + } + + return false; + } + + export function isInTemplateString(sourceFile: SourceFile, position: number) { + let token = getTokenAtPosition(sourceFile, position); + return isTemplateLiteralKind(token.kind) && position > token.getStart(sourceFile); + } + /** * Returns true if the cursor at position in sourceFile is within a comment that additionally * satisfies predicate, and false otherwise. @@ -417,7 +457,7 @@ namespace ts { export function isInCommentHelper(sourceFile: SourceFile, position: number, predicate?: (c: CommentRange) => boolean): boolean { let token = getTokenAtPosition(sourceFile, position); - if (token && position <= token.getStart()) { + if (token && position <= token.getStart(sourceFile)) { let commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); // The end marker of a single-line comment does not include the newline character. diff --git a/tests/cases/fourslash/commentBraceCompletionPosition.ts b/tests/cases/fourslash/commentBraceCompletionPosition.ts new file mode 100644 index 00000000000..23b8240dcaf --- /dev/null +++ b/tests/cases/fourslash/commentBraceCompletionPosition.ts @@ -0,0 +1,23 @@ +/// + +//// /** +//// * inside jsdoc /*1*/ +//// */ +//// function f() { +//// // inside regular comment /*2*/ +//// var c = ""; +//// +//// /* inside multi- +//// line comment /*3*/ +//// */ +//// var y =12; +//// } + +goTo.marker('1'); +verify.not.isValidBraceCompletionAtPostion('('); + +goTo.marker('2'); +verify.not.isValidBraceCompletionAtPostion('('); + +goTo.marker('3'); +verify.not.isValidBraceCompletionAtPostion('('); \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index b69a757f01e..34d508d5c7e 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -136,6 +136,7 @@ declare namespace FourSlashInterface { typeDefinitionCountIs(expectedCount: number): void; definitionLocationExists(): void; verifyDefinitionsName(name: string, containerName: string): void; + isValidBraceCompletionAtPostion(openingBrace?: string): void; } class verify extends verifyNegatable { assertHasRanges(ranges: FourSlash.Range[]): void; @@ -173,6 +174,7 @@ declare namespace FourSlashInterface { noMatchingBracePositionInCurrentFile(bracePosition: number): void; DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void; noDocCommentTemplate(): void; + getScriptLexicalStructureListCount(count: number): void; getScriptLexicalStructureListContains(name: string, kind: string, fileName?: string, parentName?: string, isAdditionalSpan?: boolean, markerPosition?: number): void; navigationItemsListCount(count: number, searchValue: string, matchKind?: string): void; diff --git a/tests/cases/fourslash/jsxBraceCompletionPosition.ts b/tests/cases/fourslash/jsxBraceCompletionPosition.ts new file mode 100644 index 00000000000..c1c331435ce --- /dev/null +++ b/tests/cases/fourslash/jsxBraceCompletionPosition.ts @@ -0,0 +1,47 @@ +/// + +//@Filename: file.tsx +//// declare var React: any; +//// +//// var x =
+//// /*1*/ +////
; +//// var y =
/*4*/
+//// var z =
+//// hello /*5*/ +////
+//// var z2 =
{ /*6*/ +////
+//// var z3 =
+//// { +//// /*7*/ +//// } +////
+ +goTo.marker('1'); +verify.not.isValidBraceCompletionAtPostion('('); +verify.isValidBraceCompletionAtPostion('{'); + +goTo.marker('2'); +verify.not.isValidBraceCompletionAtPostion('('); +verify.not.isValidBraceCompletionAtPostion('{'); + +goTo.marker('3'); +verify.not.isValidBraceCompletionAtPostion('('); +verify.isValidBraceCompletionAtPostion('{'); + +goTo.marker('4'); +verify.not.isValidBraceCompletionAtPostion('('); +verify.isValidBraceCompletionAtPostion('{'); + +goTo.marker('5'); +verify.not.isValidBraceCompletionAtPostion('('); +verify.isValidBraceCompletionAtPostion('{'); + +goTo.marker('6'); +verify.not.isValidBraceCompletionAtPostion('('); +verify.isValidBraceCompletionAtPostion('{'); + +goTo.marker('7'); +verify.not.isValidBraceCompletionAtPostion('('); +verify.isValidBraceCompletionAtPostion('{'); \ No newline at end of file diff --git a/tests/cases/fourslash/stringBraceCompletionPosition.ts b/tests/cases/fourslash/stringBraceCompletionPosition.ts new file mode 100644 index 00000000000..09a9a86b0f1 --- /dev/null +++ b/tests/cases/fourslash/stringBraceCompletionPosition.ts @@ -0,0 +1,16 @@ +/// + +//// var x = "/*1*/"; +//// var x = '/*2*/'; +//// var x = "hello \ +//// /*3*/"; + +goTo.marker('1'); +verify.not.isValidBraceCompletionAtPostion('('); + +goTo.marker('2'); +verify.not.isValidBraceCompletionAtPostion('('); + +goTo.marker('3'); +verify.not.isValidBraceCompletionAtPostion('('); + diff --git a/tests/cases/fourslash/stringTemplateBraceCompletionPosition.ts b/tests/cases/fourslash/stringTemplateBraceCompletionPosition.ts new file mode 100644 index 00000000000..33bcd4d0625 --- /dev/null +++ b/tests/cases/fourslash/stringTemplateBraceCompletionPosition.ts @@ -0,0 +1,16 @@ +/// + +//// var x = `/*1*/`; +//// var y = `hello /*2*/world, ${100}how /*3*/are you{ 200 } to/*4*/day!?` + +goTo.marker('1'); +verify.not.isValidBraceCompletionAtPostion('('); + +goTo.marker('2'); +verify.not.isValidBraceCompletionAtPostion('('); + +goTo.marker('3'); +verify.not.isValidBraceCompletionAtPostion('('); + +goTo.marker('4'); +verify.not.isValidBraceCompletionAtPostion('('); diff --git a/tests/cases/fourslash/validBraceCompletionPosition.ts b/tests/cases/fourslash/validBraceCompletionPosition.ts new file mode 100644 index 00000000000..57c30c27c21 --- /dev/null +++ b/tests/cases/fourslash/validBraceCompletionPosition.ts @@ -0,0 +1,23 @@ +/// + +//// function parseInt(/*1*/){} +//// class aa/*2*/{ +//// public b/*3*/(){} +//// } +//// interface I/*4*/{} +//// var x = /*5*/{ a:true } + +goTo.marker('1'); +verify.isValidBraceCompletionAtPostion('('); + +goTo.marker('2'); +verify.isValidBraceCompletionAtPostion('('); + +goTo.marker('3'); +verify.isValidBraceCompletionAtPostion('('); + +goTo.marker('4'); +verify.isValidBraceCompletionAtPostion('('); + +goTo.marker('5'); +verify.isValidBraceCompletionAtPostion('('); \ No newline at end of file From 5814261d6c253a5ec8d6ace434d03088b4c48b7b Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Sat, 16 Apr 2016 12:57:26 -0700 Subject: [PATCH 056/110] Added tests for quick-info on string-named enum members. --- ...sEnum.ts => quickInfoDisplayPartsEnum1.ts} | 0 .../fourslash/quickInfoDisplayPartsEnum2.ts | 79 ++++++++++++++++++ .../fourslash/quickInfoDisplayPartsEnum3.ts | 80 +++++++++++++++++++ 3 files changed, 159 insertions(+) rename tests/cases/fourslash/{quickInfoDisplayPartsEnum.ts => quickInfoDisplayPartsEnum1.ts} (100%) create mode 100644 tests/cases/fourslash/quickInfoDisplayPartsEnum2.ts create mode 100644 tests/cases/fourslash/quickInfoDisplayPartsEnum3.ts diff --git a/tests/cases/fourslash/quickInfoDisplayPartsEnum.ts b/tests/cases/fourslash/quickInfoDisplayPartsEnum1.ts similarity index 100% rename from tests/cases/fourslash/quickInfoDisplayPartsEnum.ts rename to tests/cases/fourslash/quickInfoDisplayPartsEnum1.ts diff --git a/tests/cases/fourslash/quickInfoDisplayPartsEnum2.ts b/tests/cases/fourslash/quickInfoDisplayPartsEnum2.ts new file mode 100644 index 00000000000..ad08d84c1d5 --- /dev/null +++ b/tests/cases/fourslash/quickInfoDisplayPartsEnum2.ts @@ -0,0 +1,79 @@ +/// + +////enum /*1*/E { +//// /*2*/"e1", +//// /*3*/'e2' = 10, +//// /*4*/"e3" +////} +////var /*5*/eInstance: /*6*/E; +/////*7*/eInstance = /*8*/E./*9*/e1; +/////*10*/eInstance = /*11*/E./*12*/e2; +/////*13*/eInstance = /*14*/E./*15*/e3; +////const enum /*16*/constE { +//// /*17*/"e1", +//// /*18*/'e2' = 10, +//// /*19*/"e3" +////} +////var /*20*/eInstance1: /*21*/constE; +/////*22*/eInstance1 = /*23*/constE./*24*/e1; +/////*25*/eInstance1 = /*26*/constE./*27*/e2; +/////*28*/eInstance1 = /*29*/constE./*30*/e3; + +var marker = 0; +function verifyEnumDeclaration(enumName: string, instanceName: string, isConst?: boolean) { + verifyEnumDisplay(); + + verifyEnumMemberDisplay('"e1"', /*spanLength*/ 4, 0); + verifyEnumMemberDisplay("'e2'", /*spanLength*/ 4, 10); + verifyEnumMemberDisplay('"e3"', /*spanLength*/ 4, 11); + + verifyInstance(); + verifyEnumDisplay(); + + verifyInstance(); + verifyEnumDisplay(); + verifyEnumMemberDisplay('"e1"', /*spanLength*/ 2, 0); + + verifyInstance(); + verifyEnumDisplay(); + verifyEnumMemberDisplay("'e2'", /*spanLength*/ 2, 10); + + verifyInstance(); + verifyEnumDisplay(); + verifyEnumMemberDisplay('"e3"', /*spanLength*/ 2, 11); + + function verifyEnumDisplay() { + marker++; + goTo.marker(marker.toString()); + verify.verifyQuickInfoDisplayParts("enum", "", { start: test.markerByName(marker.toString()).position, length: enumName.length }, + (isConst ? [{ text: "const", kind: "keyword" }, { text: " ", kind: "space" }] : []).concat( + [{ text: "enum", kind: "keyword" }, { text: " ", kind: "space" }, { text: enumName, kind: "enumName" }]), + []);; + } + + function verifyEnumMemberDisplay(enumMemberName: string, spanLength: number, initializer: number) { + marker++; + goTo.marker(marker.toString()); + // Each of these names is a string literal, + // but since they're accessed by property accesses, + // we need to account for the quotes at the beginning and end. + verify.verifyQuickInfoDisplayParts("var", "", { start: test.markerByName(marker.toString()).position, length: spanLength }, + [{ text: "(", kind: "punctuation" }, { text: "enum member", kind: "text" }, { text: ")", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: enumName, kind: "enumName" }, { text: "[", kind: "punctuation" }, { text: enumMemberName, kind: "stringLiteral" }, { text: "]", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: "=", kind: "operator" }, { text: " ", kind: "space" }, { text: initializer.toString(), kind: "numericLiteral" }], + []); + } + + function verifyInstance() { + marker++; + goTo.marker(marker.toString()); + verify.verifyQuickInfoDisplayParts("var", "", { start: test.markerByName(marker.toString()).position, length: instanceName.length }, + [{ text: "var", kind: "keyword" }, + { text: " ", kind: "space" }, { text: instanceName, kind: "localName" }, { text: ":", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: enumName, kind: "enumName" }], + []); + } +} + +verifyEnumDeclaration("E", "eInstance"); +verifyEnumDeclaration("constE", "eInstance1", /*isConst*/ true); diff --git a/tests/cases/fourslash/quickInfoDisplayPartsEnum3.ts b/tests/cases/fourslash/quickInfoDisplayPartsEnum3.ts new file mode 100644 index 00000000000..77fbda1e317 --- /dev/null +++ b/tests/cases/fourslash/quickInfoDisplayPartsEnum3.ts @@ -0,0 +1,80 @@ +/// + +////enum /*1*/E { +//// /*2*/"e1", +//// /*3*/'e2' = 10, +//// /*4*/"e3" +////} +////var /*5*/eInstance: /*6*/E; +/////*7*/eInstance = /*8*/E[/*9*/"e1"]; +/////*10*/eInstance = /*11*/E[/*12*/"e2"]; +/////*13*/eInstance = /*14*/E[/*15*/'e3']; +////const enum /*16*/constE { +//// /*17*/"e1", +//// /*18*/'e2' = 10, +//// /*19*/"e3" +////} +////var /*20*/eInstance1: /*21*/constE; +/////*22*/eInstance1 = /*23*/constE[/*24*/"e1"]; +/////*25*/eInstance1 = /*26*/constE[/*27*/"e2"]; +/////*28*/eInstance1 = /*29*/constE[/*30*/'e3']; + +var marker = 0; +function verifyEnumDeclaration(enumName: string, instanceName: string, isConst?: boolean) { + verifyEnumDisplay(); + + verifyEnumMemberDisplay('"e1"', /*spanLength*/ 4, 0); + verifyEnumMemberDisplay("'e2'", /*spanLength*/ 4, 10); + verifyEnumMemberDisplay('"e3"', /*spanLength*/ 4, 11); + + verifyInstance(); + verifyEnumDisplay(); + + verifyInstance(); + verifyEnumDisplay(); + verifyEnumMemberDisplay('"e1"', /*spanLength*/ 4, 0); + + verifyInstance(); + verifyEnumDisplay(); + verifyEnumMemberDisplay("'e2'", /*spanLength*/ 4, 10); + + verifyInstance(); + verifyEnumDisplay(); + verifyEnumMemberDisplay('"e3"', /*spanLength*/ 4, 11); + + function verifyEnumDisplay() { + marker++; + goTo.marker(marker.toString()); + verify.verifyQuickInfoDisplayParts("enum", "", { start: test.markerByName(marker.toString()).position, length: enumName.length }, + (isConst ? [{ text: "const", kind: "keyword" }, { text: " ", kind: "space" }] : []).concat( + [{ text: "enum", kind: "keyword" }, { text: " ", kind: "space" }, { text: enumName, kind: "enumName" }]), + []);; + } + + function verifyEnumMemberDisplay(enumMemberName: string, spanLength: number, initializer: number) { + marker++; + goTo.marker(marker.toString()); + // Each of these names is a string literal, + // but since they're accessed by property accesses, + // we need to account for the quotes at the beginning and end. + verify.verifyQuickInfoDisplayParts("var", "", { start: test.markerByName(marker.toString()).position, length: spanLength }, + [{ text: "(", kind: "punctuation" }, { text: "enum member", kind: "text" }, { text: ")", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: enumName, kind: "enumName" }, { text: "[", kind: "punctuation" }, { text: enumMemberName, kind: "stringLiteral" }, { text: "]", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: "=", kind: "operator" }, { text: " ", kind: "space" }, { text: initializer.toString(), kind: "numericLiteral" }], + []); + } + + function verifyInstance() { + marker++; + goTo.marker(marker.toString()); + verify.verifyQuickInfoDisplayParts("var", "", { start: test.markerByName(marker.toString()).position, length: instanceName.length }, + [{ text: "var", kind: "keyword" }, + { text: " ", kind: "space" }, { text: instanceName, kind: "localName" }, { text: ":", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: enumName, kind: "enumName" }], + []); + } +} + +verifyEnumDeclaration("E", "eInstance"); +marker = 15; +//verifyEnumDeclaration("constE", "eInstance1", /*isConst*/ true); From 921efec6b8a30629352d7e36c5251f09087a8888 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 16 Apr 2016 15:11:34 -0700 Subject: [PATCH 057/110] Improved handing of evolving types in iteration statements --- src/compiler/checker.ts | 58 ++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac8c375dc99..1eeec55db8d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -180,6 +180,7 @@ namespace ts { let jsxElementClassType: Type; let deferredNodes: Node[]; + let inFlowCheck = false; const tupleTypes: Map = {}; const unionTypes: Map = {}; @@ -7528,7 +7529,11 @@ namespace ts { function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) { let key: string; - return reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : declaredType; + const saveInFlowCheck = inFlowCheck; + inFlowCheck = true; + const result = reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : declaredType; + inFlowCheck = saveInFlowCheck; + return result; function getTypeAtFlowNode(flow: FlowNode): Type { while (true) { @@ -8537,7 +8542,7 @@ namespace ts { const args = getEffectiveCallArguments(callTarget); const argIndex = indexOf(args, arg); if (argIndex >= 0) { - const signature = getResolvedSignature(callTarget); + const signature = getResolvedOrAnySignature(callTarget); return getTypeAtPosition(signature, argIndex); } return undefined; @@ -11071,6 +11076,20 @@ namespace ts { return resolveCall(node, callSignatures, candidatesOutArray, headMessage); } + function resolveSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature { + switch (node.kind) { + case SyntaxKind.CallExpression: + return resolveCallExpression(node, candidatesOutArray); + case SyntaxKind.NewExpression: + return resolveNewExpression(node, candidatesOutArray); + case SyntaxKind.TaggedTemplateExpression: + return resolveTaggedTemplateExpression(node, candidatesOutArray); + case SyntaxKind.Decorator: + return resolveDecorator(node, candidatesOutArray); + } + Debug.fail("Branch in 'resolveSignature' should be unreachable."); + } + // candidatesOutArray is passed by signature help in the language service, and collectCandidates // must fill it up with the appropriate candidate signatures function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature { @@ -11079,26 +11098,23 @@ namespace ts { // However, it is possible that either candidatesOutArray was not passed in the first time, // or that a different candidatesOutArray was passed in. Therefore, we need to redo the work // to correctly fill the candidatesOutArray. - if (!links.resolvedSignature || candidatesOutArray) { - links.resolvedSignature = anySignature; - - if (node.kind === SyntaxKind.CallExpression) { - links.resolvedSignature = resolveCallExpression(node, candidatesOutArray); - } - else if (node.kind === SyntaxKind.NewExpression) { - links.resolvedSignature = resolveNewExpression(node, candidatesOutArray); - } - else if (node.kind === SyntaxKind.TaggedTemplateExpression) { - links.resolvedSignature = resolveTaggedTemplateExpression(node, candidatesOutArray); - } - else if (node.kind === SyntaxKind.Decorator) { - links.resolvedSignature = resolveDecorator(node, candidatesOutArray); - } - else { - Debug.fail("Branch in 'getResolvedSignature' should be unreachable."); - } + const cached = links.resolvedSignature; + if (cached && cached !== anySignature && !candidatesOutArray) { + return cached; } - return links.resolvedSignature; + links.resolvedSignature = anySignature; + const result = resolveSignature(node, candidatesOutArray); + // If signature resolution originated in control flow type analysis (for example to compute the + // assigned type in a flow assignment) we don't cache the result as it may be based on temporary + // types from the control flow analysis. + links.resolvedSignature = inFlowCheck ? cached : result; + return result; + } + + function getResolvedOrAnySignature(node: CallLikeExpression) { + // If we're already in the process of resolving the given signature, don't resolve again as + // that could cause infinite recursion. Instead, return anySignature. + return getNodeLinks(node).resolvedSignature === anySignature ? anySignature : getResolvedSignature(node); } function getInferredClassType(symbol: Symbol) { From 9aea70895346bf70022037c6d3c9856c862d2387 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 16 Apr 2016 15:13:31 -0700 Subject: [PATCH 058/110] Adding tests --- .../controlFlow/controlFlowIterationErrors.ts | 48 +++++++++++++++++++ .../controlFlow/controlFlowWhileStatement.ts | 29 +++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts diff --git a/tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts b/tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts new file mode 100644 index 00000000000..a8a580150e8 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts @@ -0,0 +1,48 @@ +let cond: boolean; + +function len(s: string) { + return s.length; +} + +function f1() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = len(x); + x; + } + x; +} + +function f2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; + x = len(x); + } + x; +} + +declare function foo(x: string): number; +declare function foo(x: number): string; + +function g1() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = foo(x); + x; + } + x; +} + +function g2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; + x = foo(x); + } + x; +} diff --git a/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts b/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts index dd31114adf5..7bf49dd7224 100644 --- a/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts +++ b/tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts @@ -75,3 +75,32 @@ function g() { } x; // number } +function h1() { + let x: string | number | boolean; + x = ""; + while (x > 1) { + x; // string | number + x = 1; + x; // number + } + x; // string | number +} +declare function len(s: string | number): number; +function h2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = len(x); + x; // number + } + x; // string | number +} +function h3() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; // string | number + x = len(x); + } + x; // string | number +} From 10889a042c24ad8ce017450cb076404c0076ee0d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 16 Apr 2016 15:13:48 -0700 Subject: [PATCH 059/110] Accepting new baselines --- .../controlFlowIterationErrors.errors.txt | 72 +++++++++++++++ .../reference/controlFlowIterationErrors.js | 92 +++++++++++++++++++ .../reference/controlFlowWhileStatement.js | 57 ++++++++++++ .../controlFlowWhileStatement.symbols | 74 +++++++++++++++ .../reference/controlFlowWhileStatement.types | 88 ++++++++++++++++++ 5 files changed, 383 insertions(+) create mode 100644 tests/baselines/reference/controlFlowIterationErrors.errors.txt create mode 100644 tests/baselines/reference/controlFlowIterationErrors.js diff --git a/tests/baselines/reference/controlFlowIterationErrors.errors.txt b/tests/baselines/reference/controlFlowIterationErrors.errors.txt new file mode 100644 index 00000000000..748bf05dfb7 --- /dev/null +++ b/tests/baselines/reference/controlFlowIterationErrors.errors.txt @@ -0,0 +1,72 @@ +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(11,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(22,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(34,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(45,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. + Type 'string' is not assignable to type 'number'. + + +==== tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts (4 errors) ==== + let cond: boolean; + + function len(s: string) { + return s.length; + } + + function f1() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = len(x); + ~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. +!!! error TS2345: Type 'number' is not assignable to type 'string'. + x; + } + x; + } + + function f2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; + x = len(x); + ~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. +!!! error TS2345: Type 'number' is not assignable to type 'string'. + } + x; + } + + declare function foo(x: string): number; + declare function foo(x: number): string; + + function g1() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = foo(x); + ~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + x; + } + x; + } + + function g2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; + x = foo(x); + ~ +!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. + } + x; + } + \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowIterationErrors.js b/tests/baselines/reference/controlFlowIterationErrors.js new file mode 100644 index 00000000000..6c4a9a0b7e0 --- /dev/null +++ b/tests/baselines/reference/controlFlowIterationErrors.js @@ -0,0 +1,92 @@ +//// [controlFlowIterationErrors.ts] +let cond: boolean; + +function len(s: string) { + return s.length; +} + +function f1() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = len(x); + x; + } + x; +} + +function f2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; + x = len(x); + } + x; +} + +declare function foo(x: string): number; +declare function foo(x: number): string; + +function g1() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = foo(x); + x; + } + x; +} + +function g2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; + x = foo(x); + } + x; +} + + +//// [controlFlowIterationErrors.js] +var cond; +function len(s) { + return s.length; +} +function f1() { + var x; + x = ""; + while (cond) { + x = len(x); + x; + } + x; +} +function f2() { + var x; + x = ""; + while (cond) { + x; + x = len(x); + } + x; +} +function g1() { + var x; + x = ""; + while (cond) { + x = foo(x); + x; + } + x; +} +function g2() { + var x; + x = ""; + while (cond) { + x; + x = foo(x); + } + x; +} diff --git a/tests/baselines/reference/controlFlowWhileStatement.js b/tests/baselines/reference/controlFlowWhileStatement.js index 2dfb716f7cc..d9faf9bd0ea 100644 --- a/tests/baselines/reference/controlFlowWhileStatement.js +++ b/tests/baselines/reference/controlFlowWhileStatement.js @@ -76,6 +76,35 @@ function g() { } x; // number } +function h1() { + let x: string | number | boolean; + x = ""; + while (x > 1) { + x; // string | number + x = 1; + x; // number + } + x; // string | number +} +declare function len(s: string | number): number; +function h2() { + let x: string | number | boolean; + x = ""; + while (cond) { + x = len(x); + x; // number + } + x; // string | number +} +function h3() { + let x: string | number | boolean; + x = ""; + while (cond) { + x; // string | number + x = len(x); + } + x; // string | number +} //// [controlFlowWhileStatement.js] @@ -157,3 +186,31 @@ function g() { } x; // number } +function h1() { + var x; + x = ""; + while (x > 1) { + x; // string | number + x = 1; + x; // number + } + x; // string | number +} +function h2() { + var x; + x = ""; + while (cond) { + x = len(x); + x; // number + } + x; // string | number +} +function h3() { + var x; + x = ""; + while (cond) { + x; // string | number + x = len(x); + } + x; // string | number +} diff --git a/tests/baselines/reference/controlFlowWhileStatement.symbols b/tests/baselines/reference/controlFlowWhileStatement.symbols index 01af3654f3c..3b4def93b45 100644 --- a/tests/baselines/reference/controlFlowWhileStatement.symbols +++ b/tests/baselines/reference/controlFlowWhileStatement.symbols @@ -180,4 +180,78 @@ function g() { x; // number >x : Symbol(x, Decl(controlFlowWhileStatement.ts, 62, 7)) } +function h1() { +>h1 : Symbol(h1, Decl(controlFlowWhileStatement.ts, 76, 1)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 78, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 78, 7)) + + while (x > 1) { +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 78, 7)) + + x; // string | number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 78, 7)) + + x = 1; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 78, 7)) + + x; // number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 78, 7)) + } + x; // string | number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 78, 7)) +} +declare function len(s: string | number): number; +>len : Symbol(len, Decl(controlFlowWhileStatement.ts, 86, 1)) +>s : Symbol(s, Decl(controlFlowWhileStatement.ts, 87, 21)) + +function h2() { +>h2 : Symbol(h2, Decl(controlFlowWhileStatement.ts, 87, 49)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 89, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 89, 7)) + + while (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x = len(x); +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 89, 7)) +>len : Symbol(len, Decl(controlFlowWhileStatement.ts, 86, 1)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 89, 7)) + + x; // number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 89, 7)) + } + x; // string | number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 89, 7)) +} +function h3() { +>h3 : Symbol(h3, Decl(controlFlowWhileStatement.ts, 96, 1)) + + let x: string | number | boolean; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 98, 7)) + + x = ""; +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 98, 7)) + + while (cond) { +>cond : Symbol(cond, Decl(controlFlowWhileStatement.ts, 0, 3)) + + x; // string | number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 98, 7)) + + x = len(x); +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 98, 7)) +>len : Symbol(len, Decl(controlFlowWhileStatement.ts, 86, 1)) +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 98, 7)) + } + x; // string | number +>x : Symbol(x, Decl(controlFlowWhileStatement.ts, 98, 7)) +} diff --git a/tests/baselines/reference/controlFlowWhileStatement.types b/tests/baselines/reference/controlFlowWhileStatement.types index 3658a20897a..a17c084228b 100644 --- a/tests/baselines/reference/controlFlowWhileStatement.types +++ b/tests/baselines/reference/controlFlowWhileStatement.types @@ -219,4 +219,92 @@ function g() { x; // number >x : number } +function h1() { +>h1 : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + x = ""; +>x = "" : string +>x : string | number | boolean +>"" : string + + while (x > 1) { +>x > 1 : boolean +>x : string | number +>1 : number + + x; // string | number +>x : string | number + + x = 1; +>x = 1 : number +>x : string | number | boolean +>1 : number + + x; // number +>x : number + } + x; // string | number +>x : string | number +} +declare function len(s: string | number): number; +>len : (s: string | number) => number +>s : string | number + +function h2() { +>h2 : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + x = ""; +>x = "" : string +>x : string | number | boolean +>"" : string + + while (cond) { +>cond : boolean + + x = len(x); +>x = len(x) : number +>x : string | number | boolean +>len(x) : number +>len : (s: string | number) => number +>x : string | number + + x; // number +>x : number + } + x; // string | number +>x : string | number +} +function h3() { +>h3 : () => void + + let x: string | number | boolean; +>x : string | number | boolean + + x = ""; +>x = "" : string +>x : string | number | boolean +>"" : string + + while (cond) { +>cond : boolean + + x; // string | number +>x : string | number + + x = len(x); +>x = len(x) : number +>x : string | number | boolean +>len(x) : number +>len : (s: string | number) => number +>x : string | number + } + x; // string | number +>x : string | number +} From c05fac72fba8d700e8e0f7b32ebeb3e3905199e7 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Sat, 16 Apr 2016 12:58:12 -0700 Subject: [PATCH 060/110] Use an element access when displaying literal members. --- src/compiler/checker.ts | 40 +++++++++++++++++++++++++++++++++------ src/compiler/utilities.ts | 4 ++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5e001347e06..761c6b2414d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1808,12 +1808,38 @@ namespace ts { /** * Writes only the name of the symbol out to the writer. Uses the original source text - * for the name of the symbol if it is available to match how the user inputted the name. + * for the name of the symbol if it is available to match how the user wrote the name. */ function appendSymbolNameOnly(symbol: Symbol, writer: SymbolWriter): void { writer.writeSymbol(getNameOfSymbol(symbol), symbol); } + /** + * Writes a property access or element access with the name of the symbol out to the writer. + * Uses the original source text for the name of the symbol if it is available to match how the user wrote the name, + * ensuring that any names written with literals use element accesses. + */ + function appendPropertyOrElementAccessForSymbol(symbol: Symbol, writer: SymbolWriter): void { + const symbolName = getNameOfSymbol(symbol); + const firstChar = symbolName.charCodeAt(0); + const needsElementAccess = !isIdentifierStart(firstChar, languageVersion); + + if (needsElementAccess) { + writePunctuation(writer, SyntaxKind.OpenBracketToken); + if (isSingleOrDoubleQuote(firstChar)) { + writer.writeStringLiteral(symbolName); + } + else { + writer.writeSymbol(symbolName, symbol); + } + writePunctuation(writer, SyntaxKind.CloseBracketToken); + } + else { + writePunctuation(writer, SyntaxKind.DotToken); + writer.writeSymbol(symbolName, symbol); + } + } + /** * Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope * Meaning needs to be specified if the enclosing declaration is given @@ -1832,10 +1858,12 @@ namespace ts { buildTypeParameterDisplayFromSymbol(parentSymbol, writer, enclosingDeclaration); } } - writePunctuation(writer, SyntaxKind.DotToken); + appendPropertyOrElementAccessForSymbol(symbol, writer); + } + else { + appendSymbolNameOnly(symbol, writer); } parentSymbol = symbol; - appendSymbolNameOnly(symbol, writer); } // const the writer know we just wrote out a symbol. The declaration emitter writer uses @@ -2030,10 +2058,10 @@ namespace ts { if (symbol) { // Always use 'typeof T' for type of class, enum, and module objects if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { - writeTypeofSymbol(type, flags); + writeTypeOSymbol(type, flags); } else if (shouldWriteTypeOfFunctionSymbol()) { - writeTypeofSymbol(type, flags); + writeTypeOSymbol(type, flags); } else if (contains(symbolStack, symbol)) { // If type is an anonymous type literal in a type alias declaration, use type alias name @@ -2078,7 +2106,7 @@ namespace ts { } } - function writeTypeofSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) { + function writeTypeOSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) { writeKeyword(writer, SyntaxKind.TypeOfKeyword); writeSpace(writer); buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 660f12b99e0..e9f63918bbd 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1196,6 +1196,10 @@ namespace ts { return isRequire && (!checkArgumentIsStringLiteral || (expression).arguments[0].kind === SyntaxKind.StringLiteral); } + export function isSingleOrDoubleQuote(charCode: number) { + return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote; + } + /// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property /// assignments we treat as special in the binder export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind { From a07e25a0a804a893191261b2dfcd21867036a50e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Sat, 16 Apr 2016 19:18:03 -0700 Subject: [PATCH 061/110] Added another fourslash test. --- ...quickInfoDisplayPartsLiteralLikeNames01.ts | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tests/cases/fourslash/quickInfoDisplayPartsLiteralLikeNames01.ts diff --git a/tests/cases/fourslash/quickInfoDisplayPartsLiteralLikeNames01.ts b/tests/cases/fourslash/quickInfoDisplayPartsLiteralLikeNames01.ts new file mode 100644 index 00000000000..939eb55610d --- /dev/null +++ b/tests/cases/fourslash/quickInfoDisplayPartsLiteralLikeNames01.ts @@ -0,0 +1,49 @@ +/// + +////class C { +//// public /*1*/1() { } +//// private /*2*/Infinity() { } +//// protected /*3*/NaN() { } +//// static /*4*/"stringLiteralName"() { } +//// method() { +//// this[/*5*/1](); +//// this[/*6*/"1"](); +//// this./*7*/Infinity(); +//// this[/*8*/"Infinity"](); +//// this./*9*/NaN(); +//// C./*10*/stringLiteralName(); +//// } + +verifyClassMethodWithElementAccessDisplay("1", "public", "1", "methodName", /*spanLength*/ "1".length); +verifyClassMethodWithPropertyAccessDisplay("2", "private", "Infinity", /*spanLength*/ "Infinity".length); +verifyClassMethodWithPropertyAccessDisplay("3", "protected", "NaN", /*spanLength*/ "NaN".length); +verifyClassMethodWithElementAccessDisplay("4", "static", '"stringLiteralName"', "stringLiteral", /*spanLength*/ '"stringLiteralName"'.length); +verifyClassMethodWithElementAccessDisplay("5", "public", "1", "methodName", /*spanLength*/ "1".length); +verifyClassMethodWithElementAccessDisplay("6", "public", "1", "methodName", /*spanLength*/ "1".length + 2); +verifyClassMethodWithPropertyAccessDisplay("7", "private", "Infinity", /*spanLength*/ "Infinity".length); +verifyClassMethodWithPropertyAccessDisplay("8", "private", "Infinity", /*spanLength*/ "Infinity".length + 2); +verifyClassMethodWithPropertyAccessDisplay("9", "protected", "NaN", /*spanLength*/ "NaN".length); +verifyClassMethodWithElementAccessDisplay("10", "static", '"stringLiteralName"', "stringLiteral", /*spanLength*/ "stringLiteralName".length); + + +function verifyClassMethodWithPropertyAccessDisplay(markerName: string, kindModifiers: string, methodName: string, spanLength: number) { + goTo.marker(markerName); + verify.verifyQuickInfoDisplayParts("method", kindModifiers, { start: test.markerByName(markerName).position, length: spanLength }, + [{ text: "(", kind: "punctuation" }, { text: "method", kind: "text" }, { text: ")", kind: "punctuation" }, + { text: " ", kind: "space" }, + { text: "C", kind: "className" }, { text: ".", kind: "punctuation" }, { text: methodName, kind: "methodName" }, + { text: "(", kind: "punctuation" }, { text: ")", kind: "punctuation" }, { text: ":", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: "void", kind: "keyword" }], + []); +} + +function verifyClassMethodWithElementAccessDisplay(markerName: string, kindModifiers: string, methodName: string, methodDisplay: "methodName" | "stringLiteral", spanLength: number) { + goTo.marker(markerName); + verify.verifyQuickInfoDisplayParts("method", kindModifiers, { start: test.markerByName(markerName).position, length: spanLength }, + [{ text: "(", kind: "punctuation" }, { text: "method", kind: "text" }, { text: ")", kind: "punctuation" }, + { text: " ", kind: "space" }, + { text: "C", kind: "className" }, { text: "[", kind: "punctuation" }, { text: methodName, kind: methodDisplay }, { text: "]", kind: "punctuation" }, + { text: "(", kind: "punctuation" }, { text: ")", kind: "punctuation" }, { text: ":", kind: "punctuation" }, + { text: " ", kind: "space" }, { text: "void", kind: "keyword" }], + []); +} From ac1d2187cef1eb2dc9ef02910fcbde4233122c2a Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Sat, 16 Apr 2016 19:23:13 -0700 Subject: [PATCH 062/110] Accepted symbol baselines. --- .../reference/constIndexedAccess.symbols | 4 +- .../reference/indexersInClassType.symbols | 6 +- .../negateOperatorWithEnumType.symbols | 2 +- .../reference/newWithSpreadES5.symbols | 24 +++--- .../reference/newWithSpreadES6.symbols | 24 +++--- .../reference/numericIndexingResults.symbols | 16 ++-- .../objectTypeWithNumericProperty.symbols | 16 ++-- ...TypeWithStringNamedNumericProperty.symbols | 80 +++++++++---------- ...ngNamedPropertyOfIllegalCharacters.symbols | 12 +-- .../propertyNamesWithStringLiteral.symbols | 6 +- .../reference/quotedPropertyName3.symbols | 2 +- ...aticMemberWithStringAndNumberNames.symbols | 12 +-- .../stringNamedPropertyAccess.symbols | 6 +- .../reference/tsxElementResolution.symbols | 2 +- 14 files changed, 106 insertions(+), 106 deletions(-) diff --git a/tests/baselines/reference/constIndexedAccess.symbols b/tests/baselines/reference/constIndexedAccess.symbols index 2ccb7f11686..f7ce6b78c2d 100644 --- a/tests/baselines/reference/constIndexedAccess.symbols +++ b/tests/baselines/reference/constIndexedAccess.symbols @@ -24,12 +24,12 @@ let test: indexAccess; let s = test[0]; >s : Symbol(s, Decl(constIndexedAccess.ts, 13, 3)) >test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) ->0 : Symbol(indexAccess.0, Decl(constIndexedAccess.ts, 6, 23)) +>0 : Symbol(indexAccess[0], Decl(constIndexedAccess.ts, 6, 23)) let n = test[1]; >n : Symbol(n, Decl(constIndexedAccess.ts, 14, 3)) >test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) ->1 : Symbol(indexAccess.1, Decl(constIndexedAccess.ts, 7, 14)) +>1 : Symbol(indexAccess[1], Decl(constIndexedAccess.ts, 7, 14)) let s1 = test[numbers.zero]; >s1 : Symbol(s1, Decl(constIndexedAccess.ts, 16, 3)) diff --git a/tests/baselines/reference/indexersInClassType.symbols b/tests/baselines/reference/indexersInClassType.symbols index 27c64845e92..c57c7cf7522 100644 --- a/tests/baselines/reference/indexersInClassType.symbols +++ b/tests/baselines/reference/indexersInClassType.symbols @@ -36,12 +36,12 @@ var r = c.fn(); var r2 = r[1]; >r2 : Symbol(r2, Decl(indexersInClassType.ts, 13, 3)) >r : Symbol(r, Decl(indexersInClassType.ts, 12, 3)) ->1 : Symbol(C.1, Decl(indexersInClassType.ts, 2, 24)) +>1 : Symbol(C[1], Decl(indexersInClassType.ts, 2, 24)) var r3 = r.a >r3 : Symbol(r3, Decl(indexersInClassType.ts, 14, 3)) ->r.a : Symbol(C.'a', Decl(indexersInClassType.ts, 3, 12)) +>r.a : Symbol(C['a'], Decl(indexersInClassType.ts, 3, 12)) >r : Symbol(r, Decl(indexersInClassType.ts, 12, 3)) ->a : Symbol(C.'a', Decl(indexersInClassType.ts, 3, 12)) +>a : Symbol(C['a'], Decl(indexersInClassType.ts, 3, 12)) diff --git a/tests/baselines/reference/negateOperatorWithEnumType.symbols b/tests/baselines/reference/negateOperatorWithEnumType.symbols index 9d97cda0466..98af23bb121 100644 --- a/tests/baselines/reference/negateOperatorWithEnumType.symbols +++ b/tests/baselines/reference/negateOperatorWithEnumType.symbols @@ -26,7 +26,7 @@ var ResultIsNumber3 = -(ENUM1.B + ENUM1[""]); >ENUM1 : Symbol(ENUM1, Decl(negateOperatorWithEnumType.ts, 2, 14)) >B : Symbol(ENUM1.B, Decl(negateOperatorWithEnumType.ts, 3, 15)) >ENUM1 : Symbol(ENUM1, Decl(negateOperatorWithEnumType.ts, 2, 14)) ->"" : Symbol(ENUM1."", Decl(negateOperatorWithEnumType.ts, 3, 18)) +>"" : Symbol(ENUM1[""], Decl(negateOperatorWithEnumType.ts, 3, 18)) // miss assignment operators -ENUM; diff --git a/tests/baselines/reference/newWithSpreadES5.symbols b/tests/baselines/reference/newWithSpreadES5.symbols index 4494063e2fa..7db4e6f1063 100644 --- a/tests/baselines/reference/newWithSpreadES5.symbols +++ b/tests/baselines/reference/newWithSpreadES5.symbols @@ -202,61 +202,61 @@ new B(1, 2, ...a, "string"); // Property access expression new c["a-b"](1, 2, "string"); >c : Symbol(c, Decl(newWithSpreadES5.ts, 26, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) new c["a-b"](1, 2, ...a); >c : Symbol(c, Decl(newWithSpreadES5.ts, 26, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) new c["a-b"](1, 2, ...a, "string"); >c : Symbol(c, Decl(newWithSpreadES5.ts, 26, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) // Parenthesised expression new (c["a-b"])(1, 2, "string"); >c : Symbol(c, Decl(newWithSpreadES5.ts, 26, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) new (c["a-b"])(1, 2, ...a); >c : Symbol(c, Decl(newWithSpreadES5.ts, 26, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) new (c["a-b"])(1, 2, ...a, "string"); >c : Symbol(c, Decl(newWithSpreadES5.ts, 26, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) // Element access expression new g[1]["a-b"](1, 2, "string"); >g : Symbol(g, Decl(newWithSpreadES5.ts, 29, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) new g[1]["a-b"](1, 2, ...a); >g : Symbol(g, Decl(newWithSpreadES5.ts, 29, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) new g[1]["a-b"](1, 2, ...a, "string"); >g : Symbol(g, Decl(newWithSpreadES5.ts, 29, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) // Element access expression with a punctuated key new h["a-b"]["a-b"](1, 2, "string"); >h : Symbol(h, Decl(newWithSpreadES5.ts, 30, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) new h["a-b"]["a-b"](1, 2, ...a); >h : Symbol(h, Decl(newWithSpreadES5.ts, 30, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) new h["a-b"]["a-b"](1, 2, ...a, "string"); >h : Symbol(h, Decl(newWithSpreadES5.ts, 30, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES5.ts, 16, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES5.ts, 16, 13)) >a : Symbol(a, Decl(newWithSpreadES5.ts, 24, 3)) // Element access expression with a number diff --git a/tests/baselines/reference/newWithSpreadES6.symbols b/tests/baselines/reference/newWithSpreadES6.symbols index 14e52279a27..946aeeb5c1a 100644 --- a/tests/baselines/reference/newWithSpreadES6.symbols +++ b/tests/baselines/reference/newWithSpreadES6.symbols @@ -203,61 +203,61 @@ new B(1, 2, ...a, "string"); // Property access expression new c["a-b"](1, 2, "string"); >c : Symbol(c, Decl(newWithSpreadES6.ts, 27, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) new c["a-b"](1, 2, ...a); >c : Symbol(c, Decl(newWithSpreadES6.ts, 27, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) new c["a-b"](1, 2, ...a, "string"); >c : Symbol(c, Decl(newWithSpreadES6.ts, 27, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) // Parenthesised expression new (c["a-b"])(1, 2, "string"); >c : Symbol(c, Decl(newWithSpreadES6.ts, 27, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) new (c["a-b"])(1, 2, ...a); >c : Symbol(c, Decl(newWithSpreadES6.ts, 27, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) new (c["a-b"])(1, 2, ...a, "string"); >c : Symbol(c, Decl(newWithSpreadES6.ts, 27, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) // Element access expression new g[1]["a-b"](1, 2, "string"); >g : Symbol(g, Decl(newWithSpreadES6.ts, 30, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) new g[1]["a-b"](1, 2, ...a); >g : Symbol(g, Decl(newWithSpreadES6.ts, 30, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) new g[1]["a-b"](1, 2, ...a, "string"); >g : Symbol(g, Decl(newWithSpreadES6.ts, 30, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) // Element access expression with a punctuated key new h["a-b"]["a-b"](1, 2, "string"); >h : Symbol(h, Decl(newWithSpreadES6.ts, 31, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) new h["a-b"]["a-b"](1, 2, ...a); >h : Symbol(h, Decl(newWithSpreadES6.ts, 31, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) new h["a-b"]["a-b"](1, 2, ...a, "string"); >h : Symbol(h, Decl(newWithSpreadES6.ts, 31, 3)) ->"a-b" : Symbol(C."a-b", Decl(newWithSpreadES6.ts, 17, 13)) +>"a-b" : Symbol(C["a-b"], Decl(newWithSpreadES6.ts, 17, 13)) >a : Symbol(a, Decl(newWithSpreadES6.ts, 25, 3)) // Element access expression with a number diff --git a/tests/baselines/reference/numericIndexingResults.symbols b/tests/baselines/reference/numericIndexingResults.symbols index 16a6e9386da..49a38fef567 100644 --- a/tests/baselines/reference/numericIndexingResults.symbols +++ b/tests/baselines/reference/numericIndexingResults.symbols @@ -16,12 +16,12 @@ var c: C; var r1 = c['1']; >r1 : Symbol(r1, Decl(numericIndexingResults.ts, 7, 3), Decl(numericIndexingResults.ts, 21, 3), Decl(numericIndexingResults.ts, 34, 3)) >c : Symbol(c, Decl(numericIndexingResults.ts, 6, 3)) ->'1' : Symbol(C.1, Decl(numericIndexingResults.ts, 1, 24)) +>'1' : Symbol(C[1], Decl(numericIndexingResults.ts, 1, 24)) var r2 = c['2']; >r2 : Symbol(r2, Decl(numericIndexingResults.ts, 8, 3), Decl(numericIndexingResults.ts, 22, 3), Decl(numericIndexingResults.ts, 35, 3)) >c : Symbol(c, Decl(numericIndexingResults.ts, 6, 3)) ->'2' : Symbol(C."2", Decl(numericIndexingResults.ts, 2, 11)) +>'2' : Symbol(C["2"], Decl(numericIndexingResults.ts, 2, 11)) var r3 = c['3']; >r3 : Symbol(r3, Decl(numericIndexingResults.ts, 9, 3), Decl(numericIndexingResults.ts, 23, 3), Decl(numericIndexingResults.ts, 36, 3), Decl(numericIndexingResults.ts, 44, 3), Decl(numericIndexingResults.ts, 52, 3)) @@ -30,12 +30,12 @@ var r3 = c['3']; var r4 = c[1]; >r4 : Symbol(r4, Decl(numericIndexingResults.ts, 10, 3), Decl(numericIndexingResults.ts, 24, 3), Decl(numericIndexingResults.ts, 37, 3), Decl(numericIndexingResults.ts, 45, 3), Decl(numericIndexingResults.ts, 53, 3)) >c : Symbol(c, Decl(numericIndexingResults.ts, 6, 3)) ->1 : Symbol(C.1, Decl(numericIndexingResults.ts, 1, 24)) +>1 : Symbol(C[1], Decl(numericIndexingResults.ts, 1, 24)) var r5 = c[2]; >r5 : Symbol(r5, Decl(numericIndexingResults.ts, 11, 3), Decl(numericIndexingResults.ts, 25, 3), Decl(numericIndexingResults.ts, 38, 3), Decl(numericIndexingResults.ts, 46, 3), Decl(numericIndexingResults.ts, 54, 3)) >c : Symbol(c, Decl(numericIndexingResults.ts, 6, 3)) ->2 : Symbol(C."2", Decl(numericIndexingResults.ts, 2, 11)) +>2 : Symbol(C["2"], Decl(numericIndexingResults.ts, 2, 11)) var r6 = c[3]; >r6 : Symbol(r6, Decl(numericIndexingResults.ts, 12, 3), Decl(numericIndexingResults.ts, 26, 3), Decl(numericIndexingResults.ts, 39, 3), Decl(numericIndexingResults.ts, 47, 3), Decl(numericIndexingResults.ts, 55, 3)) @@ -58,12 +58,12 @@ var i: I var r1 = i['1']; >r1 : Symbol(r1, Decl(numericIndexingResults.ts, 7, 3), Decl(numericIndexingResults.ts, 21, 3), Decl(numericIndexingResults.ts, 34, 3)) >i : Symbol(i, Decl(numericIndexingResults.ts, 20, 3)) ->'1' : Symbol(I.1, Decl(numericIndexingResults.ts, 15, 24)) +>'1' : Symbol(I[1], Decl(numericIndexingResults.ts, 15, 24)) var r2 = i['2']; >r2 : Symbol(r2, Decl(numericIndexingResults.ts, 8, 3), Decl(numericIndexingResults.ts, 22, 3), Decl(numericIndexingResults.ts, 35, 3)) >i : Symbol(i, Decl(numericIndexingResults.ts, 20, 3)) ->'2' : Symbol(I."2", Decl(numericIndexingResults.ts, 16, 14)) +>'2' : Symbol(I["2"], Decl(numericIndexingResults.ts, 16, 14)) var r3 = i['3']; >r3 : Symbol(r3, Decl(numericIndexingResults.ts, 9, 3), Decl(numericIndexingResults.ts, 23, 3), Decl(numericIndexingResults.ts, 36, 3), Decl(numericIndexingResults.ts, 44, 3), Decl(numericIndexingResults.ts, 52, 3)) @@ -72,12 +72,12 @@ var r3 = i['3']; var r4 = i[1]; >r4 : Symbol(r4, Decl(numericIndexingResults.ts, 10, 3), Decl(numericIndexingResults.ts, 24, 3), Decl(numericIndexingResults.ts, 37, 3), Decl(numericIndexingResults.ts, 45, 3), Decl(numericIndexingResults.ts, 53, 3)) >i : Symbol(i, Decl(numericIndexingResults.ts, 20, 3)) ->1 : Symbol(I.1, Decl(numericIndexingResults.ts, 15, 24)) +>1 : Symbol(I[1], Decl(numericIndexingResults.ts, 15, 24)) var r5 = i[2]; >r5 : Symbol(r5, Decl(numericIndexingResults.ts, 11, 3), Decl(numericIndexingResults.ts, 25, 3), Decl(numericIndexingResults.ts, 38, 3), Decl(numericIndexingResults.ts, 46, 3), Decl(numericIndexingResults.ts, 54, 3)) >i : Symbol(i, Decl(numericIndexingResults.ts, 20, 3)) ->2 : Symbol(I."2", Decl(numericIndexingResults.ts, 16, 14)) +>2 : Symbol(I["2"], Decl(numericIndexingResults.ts, 16, 14)) var r6 = i[3]; >r6 : Symbol(r6, Decl(numericIndexingResults.ts, 12, 3), Decl(numericIndexingResults.ts, 26, 3), Decl(numericIndexingResults.ts, 39, 3), Decl(numericIndexingResults.ts, 47, 3), Decl(numericIndexingResults.ts, 55, 3)) diff --git a/tests/baselines/reference/objectTypeWithNumericProperty.symbols b/tests/baselines/reference/objectTypeWithNumericProperty.symbols index 20e54fe1c64..73ff7149d0f 100644 --- a/tests/baselines/reference/objectTypeWithNumericProperty.symbols +++ b/tests/baselines/reference/objectTypeWithNumericProperty.symbols @@ -15,22 +15,22 @@ var c: C; var r1 = c[1]; >r1 : Symbol(r1, Decl(objectTypeWithNumericProperty.ts, 8, 3), Decl(objectTypeWithNumericProperty.ts, 19, 3), Decl(objectTypeWithNumericProperty.ts, 29, 3), Decl(objectTypeWithNumericProperty.ts, 39, 3)) >c : Symbol(c, Decl(objectTypeWithNumericProperty.ts, 7, 3)) ->1 : Symbol(C.1, Decl(objectTypeWithNumericProperty.ts, 2, 9)) +>1 : Symbol(C[1], Decl(objectTypeWithNumericProperty.ts, 2, 9)) var r2 = c[1.1]; >r2 : Symbol(r2, Decl(objectTypeWithNumericProperty.ts, 9, 3), Decl(objectTypeWithNumericProperty.ts, 20, 3), Decl(objectTypeWithNumericProperty.ts, 30, 3), Decl(objectTypeWithNumericProperty.ts, 40, 3)) >c : Symbol(c, Decl(objectTypeWithNumericProperty.ts, 7, 3)) ->1.1 : Symbol(C.1.1, Decl(objectTypeWithNumericProperty.ts, 3, 14)) +>1.1 : Symbol(C[1.1], Decl(objectTypeWithNumericProperty.ts, 3, 14)) var r3 = c['1']; >r3 : Symbol(r3, Decl(objectTypeWithNumericProperty.ts, 10, 3), Decl(objectTypeWithNumericProperty.ts, 21, 3), Decl(objectTypeWithNumericProperty.ts, 31, 3), Decl(objectTypeWithNumericProperty.ts, 41, 3)) >c : Symbol(c, Decl(objectTypeWithNumericProperty.ts, 7, 3)) ->'1' : Symbol(C.1, Decl(objectTypeWithNumericProperty.ts, 2, 9)) +>'1' : Symbol(C[1], Decl(objectTypeWithNumericProperty.ts, 2, 9)) var r4 = c['1.1']; >r4 : Symbol(r4, Decl(objectTypeWithNumericProperty.ts, 11, 3), Decl(objectTypeWithNumericProperty.ts, 22, 3), Decl(objectTypeWithNumericProperty.ts, 32, 3), Decl(objectTypeWithNumericProperty.ts, 42, 3)) >c : Symbol(c, Decl(objectTypeWithNumericProperty.ts, 7, 3)) ->'1.1' : Symbol(C.1.1, Decl(objectTypeWithNumericProperty.ts, 3, 14)) +>'1.1' : Symbol(C[1.1], Decl(objectTypeWithNumericProperty.ts, 3, 14)) interface I { >I : Symbol(I, Decl(objectTypeWithNumericProperty.ts, 11, 18)) @@ -46,22 +46,22 @@ var i: I; var r1 = i[1]; >r1 : Symbol(r1, Decl(objectTypeWithNumericProperty.ts, 8, 3), Decl(objectTypeWithNumericProperty.ts, 19, 3), Decl(objectTypeWithNumericProperty.ts, 29, 3), Decl(objectTypeWithNumericProperty.ts, 39, 3)) >i : Symbol(i, Decl(objectTypeWithNumericProperty.ts, 18, 3)) ->1 : Symbol(I.1, Decl(objectTypeWithNumericProperty.ts, 13, 13)) +>1 : Symbol(I[1], Decl(objectTypeWithNumericProperty.ts, 13, 13)) var r2 = i[1.1]; >r2 : Symbol(r2, Decl(objectTypeWithNumericProperty.ts, 9, 3), Decl(objectTypeWithNumericProperty.ts, 20, 3), Decl(objectTypeWithNumericProperty.ts, 30, 3), Decl(objectTypeWithNumericProperty.ts, 40, 3)) >i : Symbol(i, Decl(objectTypeWithNumericProperty.ts, 18, 3)) ->1.1 : Symbol(I.1.1, Decl(objectTypeWithNumericProperty.ts, 14, 14)) +>1.1 : Symbol(I[1.1], Decl(objectTypeWithNumericProperty.ts, 14, 14)) var r3 = i['1']; >r3 : Symbol(r3, Decl(objectTypeWithNumericProperty.ts, 10, 3), Decl(objectTypeWithNumericProperty.ts, 21, 3), Decl(objectTypeWithNumericProperty.ts, 31, 3), Decl(objectTypeWithNumericProperty.ts, 41, 3)) >i : Symbol(i, Decl(objectTypeWithNumericProperty.ts, 18, 3)) ->'1' : Symbol(I.1, Decl(objectTypeWithNumericProperty.ts, 13, 13)) +>'1' : Symbol(I[1], Decl(objectTypeWithNumericProperty.ts, 13, 13)) var r4 = i['1.1']; >r4 : Symbol(r4, Decl(objectTypeWithNumericProperty.ts, 11, 3), Decl(objectTypeWithNumericProperty.ts, 22, 3), Decl(objectTypeWithNumericProperty.ts, 32, 3), Decl(objectTypeWithNumericProperty.ts, 42, 3)) >i : Symbol(i, Decl(objectTypeWithNumericProperty.ts, 18, 3)) ->'1.1' : Symbol(I.1.1, Decl(objectTypeWithNumericProperty.ts, 14, 14)) +>'1.1' : Symbol(I[1.1], Decl(objectTypeWithNumericProperty.ts, 14, 14)) var a: { >a : Symbol(a, Decl(objectTypeWithNumericProperty.ts, 24, 3)) diff --git a/tests/baselines/reference/objectTypeWithStringNamedNumericProperty.symbols b/tests/baselines/reference/objectTypeWithStringNamedNumericProperty.symbols index a3f316b1bbf..480886711d5 100644 --- a/tests/baselines/reference/objectTypeWithStringNamedNumericProperty.symbols +++ b/tests/baselines/reference/objectTypeWithStringNamedNumericProperty.symbols @@ -31,47 +31,47 @@ var c: C; var r1 = c['0.1']; >r1 : Symbol(r1, Decl(objectTypeWithStringNamedNumericProperty.ts, 17, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 48, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 78, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 108, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->'0.1' : Symbol(C."0.1", Decl(objectTypeWithStringNamedNumericProperty.ts, 5, 9)) +>'0.1' : Symbol(C["0.1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 5, 9)) var r2 = c['.1']; >r2 : Symbol(r2, Decl(objectTypeWithStringNamedNumericProperty.ts, 18, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 49, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 79, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 109, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->'.1' : Symbol(C.".1", Decl(objectTypeWithStringNamedNumericProperty.ts, 6, 16)) +>'.1' : Symbol(C[".1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 6, 16)) var r3 = c['1']; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->'1' : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>'1' : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r3 = c[1]; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r4 = c['1.']; >r4 : Symbol(r4, Decl(objectTypeWithStringNamedNumericProperty.ts, 21, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 52, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 82, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 112, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->'1.' : Symbol(C."1.", Decl(objectTypeWithStringNamedNumericProperty.ts, 8, 16)) +>'1.' : Symbol(C["1."], Decl(objectTypeWithStringNamedNumericProperty.ts, 8, 16)) var r3 = c[1.]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1. : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1. : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r5 = c['1..']; >r5 : Symbol(r5, Decl(objectTypeWithStringNamedNumericProperty.ts, 23, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 54, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 84, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 114, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->'1..' : Symbol(C."1..", Decl(objectTypeWithStringNamedNumericProperty.ts, 9, 17)) +>'1..' : Symbol(C["1.."], Decl(objectTypeWithStringNamedNumericProperty.ts, 9, 17)) var r6 = c['1.0']; >r6 : Symbol(r6, Decl(objectTypeWithStringNamedNumericProperty.ts, 24, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 55, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 85, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 115, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->'1.0' : Symbol(C."1.0", Decl(objectTypeWithStringNamedNumericProperty.ts, 10, 19)) +>'1.0' : Symbol(C["1.0"], Decl(objectTypeWithStringNamedNumericProperty.ts, 10, 19)) var r3 = c[1.0]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1.0 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1.0 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) // BUG 823822 var r7 = i[-1]; @@ -85,17 +85,17 @@ var r7 = i[-1.0]; var r8 = i["-1.0"]; >r8 : Symbol(r8, Decl(objectTypeWithStringNamedNumericProperty.ts, 29, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 60, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 90, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 120, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1.0" : Symbol(I."-1.0", Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) +>"-1.0" : Symbol(I["-1.0"], Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) var r9 = i["-1"]; >r9 : Symbol(r9, Decl(objectTypeWithStringNamedNumericProperty.ts, 30, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 61, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 91, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 121, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1" : Symbol(I."-1", Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) +>"-1" : Symbol(I["-1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) var r10 = i[0x1] >r10 : Symbol(r10, Decl(objectTypeWithStringNamedNumericProperty.ts, 31, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 62, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 92, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 122, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->0x1 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>0x1 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r11 = i[-0x1] >r11 : Symbol(r11, Decl(objectTypeWithStringNamedNumericProperty.ts, 32, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 63, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 93, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 123, 3)) @@ -104,7 +104,7 @@ var r11 = i[-0x1] var r12 = i[01] >r12 : Symbol(r12, Decl(objectTypeWithStringNamedNumericProperty.ts, 33, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 64, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 94, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 124, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->01 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>01 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r13 = i[-01] >r13 : Symbol(r13, Decl(objectTypeWithStringNamedNumericProperty.ts, 34, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 65, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 95, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 125, 3)) @@ -137,47 +137,47 @@ var i: I; var r1 = i['0.1']; >r1 : Symbol(r1, Decl(objectTypeWithStringNamedNumericProperty.ts, 17, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 48, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 78, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 108, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->'0.1' : Symbol(I."0.1", Decl(objectTypeWithStringNamedNumericProperty.ts, 36, 13)) +>'0.1' : Symbol(I["0.1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 36, 13)) var r2 = i['.1']; >r2 : Symbol(r2, Decl(objectTypeWithStringNamedNumericProperty.ts, 18, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 49, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 79, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 109, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->'.1' : Symbol(I.".1", Decl(objectTypeWithStringNamedNumericProperty.ts, 37, 16)) +>'.1' : Symbol(I[".1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 37, 16)) var r3 = i['1']; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->'1' : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>'1' : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r3 = c[1]; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r4 = i['1.']; >r4 : Symbol(r4, Decl(objectTypeWithStringNamedNumericProperty.ts, 21, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 52, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 82, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 112, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->'1.' : Symbol(I."1.", Decl(objectTypeWithStringNamedNumericProperty.ts, 39, 16)) +>'1.' : Symbol(I["1."], Decl(objectTypeWithStringNamedNumericProperty.ts, 39, 16)) var r3 = c[1.]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1. : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1. : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r5 = i['1..']; >r5 : Symbol(r5, Decl(objectTypeWithStringNamedNumericProperty.ts, 23, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 54, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 84, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 114, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->'1..' : Symbol(I."1..", Decl(objectTypeWithStringNamedNumericProperty.ts, 40, 17)) +>'1..' : Symbol(I["1.."], Decl(objectTypeWithStringNamedNumericProperty.ts, 40, 17)) var r6 = i['1.0']; >r6 : Symbol(r6, Decl(objectTypeWithStringNamedNumericProperty.ts, 24, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 55, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 85, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 115, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->'1.0' : Symbol(I."1.0", Decl(objectTypeWithStringNamedNumericProperty.ts, 41, 19)) +>'1.0' : Symbol(I["1.0"], Decl(objectTypeWithStringNamedNumericProperty.ts, 41, 19)) var r3 = c[1.0]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1.0 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1.0 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) // BUG 823822 var r7 = i[-1]; @@ -191,17 +191,17 @@ var r7 = i[-1.0]; var r8 = i["-1.0"]; >r8 : Symbol(r8, Decl(objectTypeWithStringNamedNumericProperty.ts, 29, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 60, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 90, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 120, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1.0" : Symbol(I."-1.0", Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) +>"-1.0" : Symbol(I["-1.0"], Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) var r9 = i["-1"]; >r9 : Symbol(r9, Decl(objectTypeWithStringNamedNumericProperty.ts, 30, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 61, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 91, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 121, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1" : Symbol(I."-1", Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) +>"-1" : Symbol(I["-1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) var r10 = i[0x1] >r10 : Symbol(r10, Decl(objectTypeWithStringNamedNumericProperty.ts, 31, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 62, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 92, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 122, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->0x1 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>0x1 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r11 = i[-0x1] >r11 : Symbol(r11, Decl(objectTypeWithStringNamedNumericProperty.ts, 32, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 63, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 93, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 123, 3)) @@ -210,7 +210,7 @@ var r11 = i[-0x1] var r12 = i[01] >r12 : Symbol(r12, Decl(objectTypeWithStringNamedNumericProperty.ts, 33, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 64, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 94, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 124, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->01 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>01 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r13 = i[-01] >r13 : Symbol(r13, Decl(objectTypeWithStringNamedNumericProperty.ts, 34, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 65, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 95, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 125, 3)) @@ -254,7 +254,7 @@ var r3 = a['1']; var r3 = c[1]; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r4 = a['1.']; >r4 : Symbol(r4, Decl(objectTypeWithStringNamedNumericProperty.ts, 21, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 52, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 82, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 112, 3)) @@ -264,7 +264,7 @@ var r4 = a['1.']; var r3 = c[1.]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1. : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1. : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r5 = a['1..']; >r5 : Symbol(r5, Decl(objectTypeWithStringNamedNumericProperty.ts, 23, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 54, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 84, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 114, 3)) @@ -279,7 +279,7 @@ var r6 = a['1.0']; var r3 = c[1.0]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1.0 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1.0 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) // BUG 823822 var r7 = i[-1]; @@ -293,17 +293,17 @@ var r7 = i[-1.0]; var r8 = i["-1.0"]; >r8 : Symbol(r8, Decl(objectTypeWithStringNamedNumericProperty.ts, 29, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 60, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 90, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 120, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1.0" : Symbol(I."-1.0", Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) +>"-1.0" : Symbol(I["-1.0"], Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) var r9 = i["-1"]; >r9 : Symbol(r9, Decl(objectTypeWithStringNamedNumericProperty.ts, 30, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 61, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 91, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 121, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1" : Symbol(I."-1", Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) +>"-1" : Symbol(I["-1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) var r10 = i[0x1] >r10 : Symbol(r10, Decl(objectTypeWithStringNamedNumericProperty.ts, 31, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 62, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 92, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 122, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->0x1 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>0x1 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r11 = i[-0x1] >r11 : Symbol(r11, Decl(objectTypeWithStringNamedNumericProperty.ts, 32, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 63, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 93, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 123, 3)) @@ -312,7 +312,7 @@ var r11 = i[-0x1] var r12 = i[01] >r12 : Symbol(r12, Decl(objectTypeWithStringNamedNumericProperty.ts, 33, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 64, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 94, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 124, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->01 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>01 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r13 = i[-01] >r13 : Symbol(r13, Decl(objectTypeWithStringNamedNumericProperty.ts, 34, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 65, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 95, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 125, 3)) @@ -355,7 +355,7 @@ var r3 = b['1']; var r3 = c[1]; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r4 = b['1.']; >r4 : Symbol(r4, Decl(objectTypeWithStringNamedNumericProperty.ts, 21, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 52, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 82, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 112, 3)) @@ -365,7 +365,7 @@ var r4 = b['1.']; var r3 = c[1.]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1. : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1. : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) var r5 = b['1..']; >r5 : Symbol(r5, Decl(objectTypeWithStringNamedNumericProperty.ts, 23, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 54, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 84, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 114, 3)) @@ -380,7 +380,7 @@ var r6 = b['1.0']; var r3 = c[1.0]; // same as indexing by 1 when done numerically >r3 : Symbol(r3, Decl(objectTypeWithStringNamedNumericProperty.ts, 19, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 20, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 22, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 25, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 50, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 51, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 53, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 56, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 80, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 81, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 83, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 86, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 110, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 111, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 113, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 116, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedNumericProperty.ts, 16, 3)) ->1.0 : Symbol(C."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) +>1.0 : Symbol(C["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 7, 17)) // BUG 823822 var r7 = i[-1]; @@ -394,17 +394,17 @@ var r7 = i[-1.0]; var r8 = i["-1.0"]; >r8 : Symbol(r8, Decl(objectTypeWithStringNamedNumericProperty.ts, 29, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 60, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 90, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 120, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1.0" : Symbol(I."-1.0", Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) +>"-1.0" : Symbol(I["-1.0"], Decl(objectTypeWithStringNamedNumericProperty.ts, 42, 16)) var r9 = i["-1"]; >r9 : Symbol(r9, Decl(objectTypeWithStringNamedNumericProperty.ts, 30, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 61, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 91, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 121, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->"-1" : Symbol(I."-1", Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) +>"-1" : Symbol(I["-1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 43, 19)) var r10 = i[0x1] >r10 : Symbol(r10, Decl(objectTypeWithStringNamedNumericProperty.ts, 31, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 62, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 92, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 122, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->0x1 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>0x1 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r11 = i[-0x1] >r11 : Symbol(r11, Decl(objectTypeWithStringNamedNumericProperty.ts, 32, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 63, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 93, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 123, 3)) @@ -413,7 +413,7 @@ var r11 = i[-0x1] var r12 = i[01] >r12 : Symbol(r12, Decl(objectTypeWithStringNamedNumericProperty.ts, 33, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 64, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 94, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 124, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedNumericProperty.ts, 47, 3)) ->01 : Symbol(I."1", Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) +>01 : Symbol(I["1"], Decl(objectTypeWithStringNamedNumericProperty.ts, 38, 17)) var r13 = i[-01] >r13 : Symbol(r13, Decl(objectTypeWithStringNamedNumericProperty.ts, 34, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 65, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 95, 3), Decl(objectTypeWithStringNamedNumericProperty.ts, 125, 3)) diff --git a/tests/baselines/reference/objectTypeWithStringNamedPropertyOfIllegalCharacters.symbols b/tests/baselines/reference/objectTypeWithStringNamedPropertyOfIllegalCharacters.symbols index aa76e7e92c8..773fb3f5760 100644 --- a/tests/baselines/reference/objectTypeWithStringNamedPropertyOfIllegalCharacters.symbols +++ b/tests/baselines/reference/objectTypeWithStringNamedPropertyOfIllegalCharacters.symbols @@ -16,7 +16,7 @@ var c: C; var r = c[" "]; >r : Symbol(r, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 9, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 22, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 35, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 47, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 8, 3)) ->" " : Symbol(C." ", Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 0, 9)) +>" " : Symbol(C[" "], Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 0, 9)) var r2 = c[" "]; >r2 : Symbol(r2, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 10, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 23, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 36, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 48, 3)) @@ -25,13 +25,13 @@ var r2 = c[" "]; var r3 = c["a b"]; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 11, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 24, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 37, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 49, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 8, 3)) ->"a b" : Symbol(C."a b", Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 1, 18)) +>"a b" : Symbol(C["a b"], Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 1, 18)) // BUG 817263 var r4 = c["~!@#$%^&*()_+{}|:'<>?\/.,`"]; >r4 : Symbol(r4, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 13, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 26, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 39, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 51, 3)) >c : Symbol(c, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 8, 3)) ->"~!@#$%^&*()_+{}|:'<>?\/.,`" : Symbol(C."~!@#$%^&*()_+{}|:'<>?\/.,`", Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 2, 20)) +>"~!@#$%^&*()_+{}|:'<>?\/.,`" : Symbol(C["~!@#$%^&*()_+{}|:'<>?\/.,`"], Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 2, 20)) interface I { >I : Symbol(I, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 13, 41)) @@ -48,7 +48,7 @@ var i: I; var r = i[" "]; >r : Symbol(r, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 9, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 22, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 35, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 47, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 21, 3)) ->" " : Symbol(I." ", Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 15, 13)) +>" " : Symbol(I[" "], Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 15, 13)) var r2 = i[" "]; >r2 : Symbol(r2, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 10, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 23, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 36, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 48, 3)) @@ -57,13 +57,13 @@ var r2 = i[" "]; var r3 = i["a b"]; >r3 : Symbol(r3, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 11, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 24, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 37, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 49, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 21, 3)) ->"a b" : Symbol(I."a b", Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 16, 18)) +>"a b" : Symbol(I["a b"], Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 16, 18)) // BUG 817263 var r4 = i["~!@#$%^&*()_+{}|:'<>?\/.,`"]; >r4 : Symbol(r4, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 13, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 26, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 39, 3), Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 51, 3)) >i : Symbol(i, Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 21, 3)) ->"~!@#$%^&*()_+{}|:'<>?\/.,`" : Symbol(I."~!@#$%^&*()_+{}|:'<>?\/.,`", Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 17, 20)) +>"~!@#$%^&*()_+{}|:'<>?\/.,`" : Symbol(I["~!@#$%^&*()_+{}|:'<>?\/.,`"], Decl(objectTypeWithStringNamedPropertyOfIllegalCharacters.ts, 17, 20)) var a: { diff --git a/tests/baselines/reference/propertyNamesWithStringLiteral.symbols b/tests/baselines/reference/propertyNamesWithStringLiteral.symbols index 3844c0891e8..1851629c134 100644 --- a/tests/baselines/reference/propertyNamesWithStringLiteral.symbols +++ b/tests/baselines/reference/propertyNamesWithStringLiteral.symbols @@ -38,16 +38,16 @@ var a = Color.namedColors["azure"]; var a = Color.namedColors.blue; // Should not error >a : Symbol(a, Decl(propertyNamesWithStringLiteral.ts, 12, 3), Decl(propertyNamesWithStringLiteral.ts, 13, 3), Decl(propertyNamesWithStringLiteral.ts, 14, 3)) ->Color.namedColors.blue : Symbol(NamedColors."blue", Decl(propertyNamesWithStringLiteral.ts, 5, 18)) +>Color.namedColors.blue : Symbol(NamedColors["blue"], Decl(propertyNamesWithStringLiteral.ts, 5, 18)) >Color.namedColors : Symbol(Color.namedColors, Decl(propertyNamesWithStringLiteral.ts, 10, 14)) >Color : Symbol(Color, Decl(propertyNamesWithStringLiteral.ts, 8, 1)) >namedColors : Symbol(Color.namedColors, Decl(propertyNamesWithStringLiteral.ts, 10, 14)) ->blue : Symbol(NamedColors."blue", Decl(propertyNamesWithStringLiteral.ts, 5, 18)) +>blue : Symbol(NamedColors["blue"], Decl(propertyNamesWithStringLiteral.ts, 5, 18)) var a = Color.namedColors["pale blue"]; // should not error >a : Symbol(a, Decl(propertyNamesWithStringLiteral.ts, 12, 3), Decl(propertyNamesWithStringLiteral.ts, 13, 3), Decl(propertyNamesWithStringLiteral.ts, 14, 3)) >Color.namedColors : Symbol(Color.namedColors, Decl(propertyNamesWithStringLiteral.ts, 10, 14)) >Color : Symbol(Color, Decl(propertyNamesWithStringLiteral.ts, 8, 1)) >namedColors : Symbol(Color.namedColors, Decl(propertyNamesWithStringLiteral.ts, 10, 14)) ->"pale blue" : Symbol(NamedColors."pale blue", Decl(propertyNamesWithStringLiteral.ts, 6, 19)) +>"pale blue" : Symbol(NamedColors["pale blue"], Decl(propertyNamesWithStringLiteral.ts, 6, 19)) diff --git a/tests/baselines/reference/quotedPropertyName3.symbols b/tests/baselines/reference/quotedPropertyName3.symbols index 2b09da7f6cc..813cf23e336 100644 --- a/tests/baselines/reference/quotedPropertyName3.symbols +++ b/tests/baselines/reference/quotedPropertyName3.symbols @@ -9,7 +9,7 @@ class Test { var x = () => this["prop1"]; >x : Symbol(x, Decl(quotedPropertyName3.ts, 3, 11)) >this : Symbol(Test, Decl(quotedPropertyName3.ts, 0, 0)) ->"prop1" : Symbol(Test."prop1", Decl(quotedPropertyName3.ts, 0, 12)) +>"prop1" : Symbol(Test["prop1"], Decl(quotedPropertyName3.ts, 0, 12)) var y: number = x(); >y : Symbol(y, Decl(quotedPropertyName3.ts, 4, 11)) diff --git a/tests/baselines/reference/staticMemberWithStringAndNumberNames.symbols b/tests/baselines/reference/staticMemberWithStringAndNumberNames.symbols index 906bd824909..277a88ce38f 100644 --- a/tests/baselines/reference/staticMemberWithStringAndNumberNames.symbols +++ b/tests/baselines/reference/staticMemberWithStringAndNumberNames.symbols @@ -8,30 +8,30 @@ class C { x = C['foo']; >x : Symbol(C.x, Decl(staticMemberWithStringAndNumberNames.ts, 2, 17)) >C : Symbol(C, Decl(staticMemberWithStringAndNumberNames.ts, 0, 0)) ->'foo' : Symbol(C."foo", Decl(staticMemberWithStringAndNumberNames.ts, 0, 9)) +>'foo' : Symbol(C["foo"], Decl(staticMemberWithStringAndNumberNames.ts, 0, 9)) x2 = C['0']; >x2 : Symbol(C.x2, Decl(staticMemberWithStringAndNumberNames.ts, 4, 17)) >C : Symbol(C, Decl(staticMemberWithStringAndNumberNames.ts, 0, 0)) ->'0' : Symbol(C.0, Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) +>'0' : Symbol(C[0], Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) x3 = C[0]; >x3 : Symbol(C.x3, Decl(staticMemberWithStringAndNumberNames.ts, 5, 16)) >C : Symbol(C, Decl(staticMemberWithStringAndNumberNames.ts, 0, 0)) ->0 : Symbol(C.0, Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) +>0 : Symbol(C[0], Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) static s = C['foo']; >s : Symbol(C.s, Decl(staticMemberWithStringAndNumberNames.ts, 6, 14)) >C : Symbol(C, Decl(staticMemberWithStringAndNumberNames.ts, 0, 0)) ->'foo' : Symbol(C."foo", Decl(staticMemberWithStringAndNumberNames.ts, 0, 9)) +>'foo' : Symbol(C["foo"], Decl(staticMemberWithStringAndNumberNames.ts, 0, 9)) static s2 = C['0']; >s2 : Symbol(C.s2, Decl(staticMemberWithStringAndNumberNames.ts, 8, 24)) >C : Symbol(C, Decl(staticMemberWithStringAndNumberNames.ts, 0, 0)) ->'0' : Symbol(C.0, Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) +>'0' : Symbol(C[0], Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) static s3 = C[0]; >s3 : Symbol(C.s3, Decl(staticMemberWithStringAndNumberNames.ts, 9, 23)) >C : Symbol(C, Decl(staticMemberWithStringAndNumberNames.ts, 0, 0)) ->0 : Symbol(C.0, Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) +>0 : Symbol(C[0], Decl(staticMemberWithStringAndNumberNames.ts, 1, 21)) } diff --git a/tests/baselines/reference/stringNamedPropertyAccess.symbols b/tests/baselines/reference/stringNamedPropertyAccess.symbols index 583e5da06ed..961b03f6e04 100644 --- a/tests/baselines/reference/stringNamedPropertyAccess.symbols +++ b/tests/baselines/reference/stringNamedPropertyAccess.symbols @@ -12,12 +12,12 @@ var c: C; var r1 = c["a b"]; >r1 : Symbol(r1, Decl(stringNamedPropertyAccess.ts, 5, 3)) >c : Symbol(c, Decl(stringNamedPropertyAccess.ts, 4, 3)) ->"a b" : Symbol(C."a b", Decl(stringNamedPropertyAccess.ts, 0, 9)) +>"a b" : Symbol(C["a b"], Decl(stringNamedPropertyAccess.ts, 0, 9)) var r1b = C['c d']; >r1b : Symbol(r1b, Decl(stringNamedPropertyAccess.ts, 6, 3)) >C : Symbol(C, Decl(stringNamedPropertyAccess.ts, 0, 0)) ->'c d' : Symbol(C."c d", Decl(stringNamedPropertyAccess.ts, 1, 18)) +>'c d' : Symbol(C["c d"], Decl(stringNamedPropertyAccess.ts, 1, 18)) interface I { >I : Symbol(I, Decl(stringNamedPropertyAccess.ts, 6, 19)) @@ -31,7 +31,7 @@ var i: I; var r2 = i["a b"]; >r2 : Symbol(r2, Decl(stringNamedPropertyAccess.ts, 12, 3)) >i : Symbol(i, Decl(stringNamedPropertyAccess.ts, 11, 3)) ->"a b" : Symbol(I."a b", Decl(stringNamedPropertyAccess.ts, 8, 13)) +>"a b" : Symbol(I["a b"], Decl(stringNamedPropertyAccess.ts, 8, 13)) var a: { >a : Symbol(a, Decl(stringNamedPropertyAccess.ts, 14, 3)) diff --git a/tests/baselines/reference/tsxElementResolution.symbols b/tests/baselines/reference/tsxElementResolution.symbols index cd7ac7807f1..729c3fc9f06 100644 --- a/tests/baselines/reference/tsxElementResolution.symbols +++ b/tests/baselines/reference/tsxElementResolution.symbols @@ -36,7 +36,7 @@ var a = ; var b = ; >b : Symbol(b, Decl(tsxElementResolution.tsx, 18, 3)) ->string_named : Symbol(JSX.IntrinsicElements.'string_named', Decl(tsxElementResolution.tsx, 3, 28)) +>string_named : Symbol(JSX.IntrinsicElements['string_named'], Decl(tsxElementResolution.tsx, 3, 28)) // TODO: This should not be a parse error (should // parse a property name here, not identifier) From 2595f0451c2930224f3cc51bca39935e77f449c5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 17 Apr 2016 13:48:41 -0700 Subject: [PATCH 063/110] Removing unused properties --- src/compiler/types.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a89f7dcca8e..b5e33d5d361 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2083,8 +2083,6 @@ namespace ts { 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) - firstAssignmentChecked?: boolean; // True if first assignment node has been computed - firstAssignment?: Node; // First assignment node (undefined if no assignments) } /* @internal */ @@ -2118,18 +2116,13 @@ namespace ts { /* @internal */ export interface NodeLinks { resolvedType?: Type; // Cached type of type node - resolvedAwaitedType?: Type; // Cached awaited type of type node resolvedSignature?: Signature; // Cached signature of signature node or call expression resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result flags?: NodeCheckFlags; // Set of flags specific to Node enumMemberValue?: number; // Constant value of enum member isVisible?: boolean; // Is this node visible - generatedName?: string; // Generated name for module, enum, or import declaration - generatedNames?: Map; // Generated names table for source file - assignmentMap?: Map; // Cached map of references assigned within this node hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context - importOnRightSide?: Symbol; // for import declarations - import that appear on the right side jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt. From 25d7229cbb020828c8f65224d3db8acd6dcb659b Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 18 Apr 2016 10:08:48 -0700 Subject: [PATCH 064/110] O -> Of --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 761c6b2414d..e989c8c8a04 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2058,10 +2058,10 @@ namespace ts { if (symbol) { // Always use 'typeof T' for type of class, enum, and module objects if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { - writeTypeOSymbol(type, flags); + writeTypeOfSymbol(type, flags); } else if (shouldWriteTypeOfFunctionSymbol()) { - writeTypeOSymbol(type, flags); + writeTypeOfSymbol(type, flags); } else if (contains(symbolStack, symbol)) { // If type is an anonymous type literal in a type alias declaration, use type alias name @@ -2106,7 +2106,7 @@ namespace ts { } } - function writeTypeOSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) { + function writeTypeOfSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) { writeKeyword(writer, SyntaxKind.TypeOfKeyword); writeSpace(writer); buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags); From d5a27a196eebcd90678a7857d590e3a502371bac Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 18 Apr 2016 10:12:40 -0700 Subject: [PATCH 065/110] Bump TS services version to 0.5. --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index d08061664bf..333baaec637 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -13,7 +13,7 @@ namespace ts { /** The version of the language service API */ - export const servicesVersion = "0.4"; + export const servicesVersion = "0.5"; export interface Node { getSourceFile(): SourceFile; From 3e2fff2150cc7c0488fa91da574b16c863877b6c Mon Sep 17 00:00:00 2001 From: Nima Zahedi Date: Mon, 18 Apr 2016 21:46:52 +0200 Subject: [PATCH 066/110] Array.prototype.filter.not.forcing.boolean (#7779) * Add test for issue * Fix issue * Add baselines * fix issue --- src/lib/es5.d.ts | 22 ++++++------- tests/baselines/reference/arrayFilter.js | 16 +++++++++ tests/baselines/reference/arrayFilter.symbols | 24 ++++++++++++++ tests/baselines/reference/arrayFilter.types | 33 +++++++++++++++++++ .../genericMethodOverspecialization.types | 4 +-- tests/cases/compiler/arrayFilter.ts | 7 ++++ 6 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 tests/baselines/reference/arrayFilter.js create mode 100644 tests/baselines/reference/arrayFilter.symbols create mode 100644 tests/baselines/reference/arrayFilter.types create mode 100644 tests/cases/compiler/arrayFilter.ts diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index 1bcf528640b..17916d5548e 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -1064,7 +1064,7 @@ interface ReadonlyArray { * @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array. * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: T, index: number, array: ReadonlyArray) => boolean, thisArg?: any): T[]; + filter(callbackfn: (value: T, index: number, array: ReadonlyArray) => any, thisArg?: any): T[]; /** * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. @@ -1199,7 +1199,7 @@ interface Array { * @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array. * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): T[]; + filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; /** * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. @@ -1511,7 +1511,7 @@ interface Int8Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Int8Array) => boolean, thisArg?: any): Int8Array; + filter(callbackfn: (value: number, index: number, array: Int8Array) => any, thisArg?: any): Int8Array; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -1784,7 +1784,7 @@ interface Uint8Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Uint8Array) => boolean, thisArg?: any): Uint8Array; + filter(callbackfn: (value: number, index: number, array: Uint8Array) => any, thisArg?: any): Uint8Array; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -2058,7 +2058,7 @@ interface Uint8ClampedArray { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Uint8ClampedArray) => boolean, thisArg?: any): Uint8ClampedArray; + filter(callbackfn: (value: number, index: number, array: Uint8ClampedArray) => any, thisArg?: any): Uint8ClampedArray; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -2331,7 +2331,7 @@ interface Int16Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Int16Array) => boolean, thisArg?: any): Int16Array; + filter(callbackfn: (value: number, index: number, array: Int16Array) => any, thisArg?: any): Int16Array; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -2605,7 +2605,7 @@ interface Uint16Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Uint16Array) => boolean, thisArg?: any): Uint16Array; + filter(callbackfn: (value: number, index: number, array: Uint16Array) => any, thisArg?: any): Uint16Array; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -2878,7 +2878,7 @@ interface Int32Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Int32Array) => boolean, thisArg?: any): Int32Array; + filter(callbackfn: (value: number, index: number, array: Int32Array) => any, thisArg?: any): Int32Array; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -3151,7 +3151,7 @@ interface Uint32Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Uint32Array) => boolean, thisArg?: any): Uint32Array; + filter(callbackfn: (value: number, index: number, array: Uint32Array) => any, thisArg?: any): Uint32Array; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -3424,7 +3424,7 @@ interface Float32Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Float32Array) => boolean, thisArg?: any): Float32Array; + filter(callbackfn: (value: number, index: number, array: Float32Array) => any, thisArg?: any): Float32Array; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -3698,7 +3698,7 @@ interface Float64Array { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - filter(callbackfn: (value: number, index: number, array: Float64Array) => boolean, thisArg?: any): Float64Array; + filter(callbackfn: (value: number, index: number, array: Float64Array) => any, thisArg?: any): Float64Array; /** * Returns the value of the first element in the array where predicate is true, and undefined diff --git a/tests/baselines/reference/arrayFilter.js b/tests/baselines/reference/arrayFilter.js new file mode 100644 index 00000000000..dd3b321b19c --- /dev/null +++ b/tests/baselines/reference/arrayFilter.js @@ -0,0 +1,16 @@ +//// [arrayFilter.ts] +var foo = [ + { name: 'bar' }, + { name: null }, + { name: 'baz' } +] + +foo.filter(x => x.name); //should accepted all possible types not only boolean! + +//// [arrayFilter.js] +var foo = [ + { name: 'bar' }, + { name: null }, + { name: 'baz' } +]; +foo.filter(function (x) { return x.name; }); //should accepted all possible types not only boolean! diff --git a/tests/baselines/reference/arrayFilter.symbols b/tests/baselines/reference/arrayFilter.symbols new file mode 100644 index 00000000000..fcdd39117a7 --- /dev/null +++ b/tests/baselines/reference/arrayFilter.symbols @@ -0,0 +1,24 @@ +=== tests/cases/compiler/arrayFilter.ts === +var foo = [ +>foo : Symbol(foo, Decl(arrayFilter.ts, 0, 3)) + + { name: 'bar' }, +>name : Symbol(name, Decl(arrayFilter.ts, 1, 5)) + + { name: null }, +>name : Symbol(name, Decl(arrayFilter.ts, 2, 5)) + + { name: 'baz' } +>name : Symbol(name, Decl(arrayFilter.ts, 3, 5)) + +] + +foo.filter(x => x.name); //should accepted all possible types not only boolean! +>foo.filter : Symbol(Array.filter, Decl(lib.d.ts, --, --)) +>foo : Symbol(foo, Decl(arrayFilter.ts, 0, 3)) +>filter : Symbol(Array.filter, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(arrayFilter.ts, 6, 11)) +>x.name : Symbol(name, Decl(arrayFilter.ts, 1, 5)) +>x : Symbol(x, Decl(arrayFilter.ts, 6, 11)) +>name : Symbol(name, Decl(arrayFilter.ts, 1, 5)) + diff --git a/tests/baselines/reference/arrayFilter.types b/tests/baselines/reference/arrayFilter.types new file mode 100644 index 00000000000..f3d6d421744 --- /dev/null +++ b/tests/baselines/reference/arrayFilter.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/arrayFilter.ts === +var foo = [ +>foo : { name: string; }[] +>[ { name: 'bar' }, { name: null }, { name: 'baz' }] : { name: string; }[] + + { name: 'bar' }, +>{ name: 'bar' } : { name: string; } +>name : string +>'bar' : string + + { name: null }, +>{ name: null } : { name: null; } +>name : null +>null : null + + { name: 'baz' } +>{ name: 'baz' } : { name: string; } +>name : string +>'baz' : string + +] + +foo.filter(x => x.name); //should accepted all possible types not only boolean! +>foo.filter(x => x.name) : { name: string; }[] +>foo.filter : (callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg?: any) => { name: string; }[] +>foo : { name: string; }[] +>filter : (callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg?: any) => { name: string; }[] +>x => x.name : (x: { name: string; }) => string +>x : { name: string; } +>x.name : string +>x : { name: string; } +>name : string + diff --git a/tests/baselines/reference/genericMethodOverspecialization.types b/tests/baselines/reference/genericMethodOverspecialization.types index 0ad302da94e..375eefaa86c 100644 --- a/tests/baselines/reference/genericMethodOverspecialization.types +++ b/tests/baselines/reference/genericMethodOverspecialization.types @@ -53,9 +53,9 @@ var elements = names.map(function (name) { var xxx = elements.filter(function (e) { >xxx : HTMLElement[] >elements.filter(function (e) { return !e.isDisabled;}) : HTMLElement[] ->elements.filter : (callbackfn: (value: HTMLElement, index: number, array: HTMLElement[]) => boolean, thisArg?: any) => HTMLElement[] +>elements.filter : (callbackfn: (value: HTMLElement, index: number, array: HTMLElement[]) => any, thisArg?: any) => HTMLElement[] >elements : HTMLElement[] ->filter : (callbackfn: (value: HTMLElement, index: number, array: HTMLElement[]) => boolean, thisArg?: any) => HTMLElement[] +>filter : (callbackfn: (value: HTMLElement, index: number, array: HTMLElement[]) => any, thisArg?: any) => HTMLElement[] >function (e) { return !e.isDisabled;} : (e: HTMLElement) => boolean >e : HTMLElement diff --git a/tests/cases/compiler/arrayFilter.ts b/tests/cases/compiler/arrayFilter.ts new file mode 100644 index 00000000000..d13dc0dc9fa --- /dev/null +++ b/tests/cases/compiler/arrayFilter.ts @@ -0,0 +1,7 @@ +var foo = [ + { name: 'bar' }, + { name: null }, + { name: 'baz' } +] + +foo.filter(x => x.name); //should accepted all possible types not only boolean! \ No newline at end of file From 87b64c5b2817afccf9501f58ea5c0c46ad1a5c3a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 18 Apr 2016 13:48:42 -0700 Subject: [PATCH 067/110] Add the test case for #8105 --- .../reference/declarationEmitPromise.js | 122 ++++++++++++ .../reference/declarationEmitPromise.symbols | 155 +++++++++++++++ .../reference/declarationEmitPromise.types | 181 ++++++++++++++++++ .../cases/compiler/declarationEmitPromise.ts | 25 +++ 4 files changed, 483 insertions(+) create mode 100644 tests/baselines/reference/declarationEmitPromise.js create mode 100644 tests/baselines/reference/declarationEmitPromise.symbols create mode 100644 tests/baselines/reference/declarationEmitPromise.types create mode 100644 tests/cases/compiler/declarationEmitPromise.ts diff --git a/tests/baselines/reference/declarationEmitPromise.js b/tests/baselines/reference/declarationEmitPromise.js new file mode 100644 index 00000000000..7387623dfe2 --- /dev/null +++ b/tests/baselines/reference/declarationEmitPromise.js @@ -0,0 +1,122 @@ +//// [declarationEmitPromise.ts] + +export class bluebird { + static all: Array>; +} + +export async function runSampleWorks( + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => + f.apply(this, result); + let rfunc: typeof func & {} = func as any; // <- This is the only difference + return rfunc +} + +export async function runSampleBreaks( + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => + f.apply(this, result); + let rfunc: typeof func = func as any; // <- This is the only difference + return rfunc +} + +//// [declarationEmitPromise.js] +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +class bluebird { +} +exports.bluebird = bluebird; +function runSampleWorks(a, b, c, d, e) { + return __awaiter(this, void 0, void 0, function* () { + let result = yield bluebird.all([a, b, c, d, e].filter(el => !!el)); + let func = (f) => f.apply(this, result); + let rfunc = func; // <- This is the only difference + return rfunc; + }); +} +exports.runSampleWorks = runSampleWorks; +function runSampleBreaks(a, b, c, d, e) { + return __awaiter(this, void 0, void 0, function* () { + let result = yield bluebird.all([a, b, c, d, e].filter(el => !!el)); + let func = (f) => f.apply(this, result); + let rfunc = func; // <- This is the only difference + return rfunc; + }); +} +exports.runSampleBreaks = runSampleBreaks; + + +//// [declarationEmitPromise.d.ts] +export declare class bluebird { + static all: Array>; +} +export declare function runSampleWorks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>; +export declare function runSampleBreaks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>; + + +//// [DtsFileErrors] + + +tests/cases/compiler/declarationEmitPromise.d.ts(5,141): error TS2314: Generic type 'Promise' requires 1 type argument(s). +tests/cases/compiler/declarationEmitPromise.d.ts(5,148): error TS1144: '{' or ';' expected. +tests/cases/compiler/declarationEmitPromise.d.ts(5,150): error TS2304: Cannot find name 'T'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,153): error TS2304: Cannot find name 'f'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,154): error TS1005: ')' expected. +tests/cases/compiler/declarationEmitPromise.d.ts(5,160): error TS2304: Cannot find name 'A'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,167): error TS2304: Cannot find name 'B'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,174): error TS2304: Cannot find name 'C'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,181): error TS2304: Cannot find name 'D'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,188): error TS2304: Cannot find name 'E'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,194): error TS2304: Cannot find name 'T'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,195): error TS1005: ';' expected. +tests/cases/compiler/declarationEmitPromise.d.ts(5,197): error TS1128: Declaration or statement expected. +tests/cases/compiler/declarationEmitPromise.d.ts(5,200): error TS2304: Cannot find name 'T'. +tests/cases/compiler/declarationEmitPromise.d.ts(5,202): error TS1109: Expression expected. + + +==== tests/cases/compiler/declarationEmitPromise.d.ts (15 errors) ==== + export declare class bluebird { + static all: Array>; + } + export declare function runSampleWorks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>; + export declare function runSampleBreaks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>; + ~~~~~~~ +!!! error TS2314: Generic type 'Promise' requires 1 type argument(s). + ~~ +!!! error TS1144: '{' or ';' expected. + ~ +!!! error TS2304: Cannot find name 'T'. + ~ +!!! error TS2304: Cannot find name 'f'. + ~ +!!! error TS1005: ')' expected. + ~ +!!! error TS2304: Cannot find name 'A'. + ~ +!!! error TS2304: Cannot find name 'B'. + ~ +!!! error TS2304: Cannot find name 'C'. + ~ +!!! error TS2304: Cannot find name 'D'. + ~ +!!! error TS2304: Cannot find name 'E'. + ~ +!!! error TS2304: Cannot find name 'T'. + ~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS1128: Declaration or statement expected. + ~ +!!! error TS2304: Cannot find name 'T'. + ~ +!!! error TS1109: Expression expected. + \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmitPromise.symbols b/tests/baselines/reference/declarationEmitPromise.symbols new file mode 100644 index 00000000000..894a20e03a6 --- /dev/null +++ b/tests/baselines/reference/declarationEmitPromise.symbols @@ -0,0 +1,155 @@ +=== tests/cases/compiler/declarationEmitPromise.ts === + +export class bluebird { +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>T : Symbol(T, Decl(declarationEmitPromise.ts, 1, 22)) + + static all: Array>; +>all : Symbol(bluebird.all, Decl(declarationEmitPromise.ts, 1, 26)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +} + +export async function runSampleWorks( +>runSampleWorks : Symbol(runSampleWorks, Decl(declarationEmitPromise.ts, 3, 1)) +>A : Symbol(A, Decl(declarationEmitPromise.ts, 5, 37)) +>B : Symbol(B, Decl(declarationEmitPromise.ts, 5, 39)) +>C : Symbol(C, Decl(declarationEmitPromise.ts, 5, 42)) +>D : Symbol(D, Decl(declarationEmitPromise.ts, 5, 45)) +>E : Symbol(E, Decl(declarationEmitPromise.ts, 5, 48)) + + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { +>a : Symbol(a, Decl(declarationEmitPromise.ts, 5, 52)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>A : Symbol(A, Decl(declarationEmitPromise.ts, 5, 37)) +>b : Symbol(b, Decl(declarationEmitPromise.ts, 6, 19)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>B : Symbol(B, Decl(declarationEmitPromise.ts, 5, 39)) +>c : Symbol(c, Decl(declarationEmitPromise.ts, 6, 36)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>C : Symbol(C, Decl(declarationEmitPromise.ts, 5, 42)) +>d : Symbol(d, Decl(declarationEmitPromise.ts, 6, 53)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>D : Symbol(D, Decl(declarationEmitPromise.ts, 5, 45)) +>e : Symbol(e, Decl(declarationEmitPromise.ts, 6, 70)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>E : Symbol(E, Decl(declarationEmitPromise.ts, 5, 48)) + + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); +>result : Symbol(result, Decl(declarationEmitPromise.ts, 7, 7)) +>bluebird.all : Symbol(bluebird.all, Decl(declarationEmitPromise.ts, 1, 26)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>all : Symbol(bluebird.all, Decl(declarationEmitPromise.ts, 1, 26)) +>[a, b, c, d, e].filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(declarationEmitPromise.ts, 5, 52)) +>b : Symbol(b, Decl(declarationEmitPromise.ts, 6, 19)) +>c : Symbol(c, Decl(declarationEmitPromise.ts, 6, 36)) +>d : Symbol(d, Decl(declarationEmitPromise.ts, 6, 53)) +>e : Symbol(e, Decl(declarationEmitPromise.ts, 6, 70)) +>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --)) +>el : Symbol(el, Decl(declarationEmitPromise.ts, 7, 68)) +>el : Symbol(el, Decl(declarationEmitPromise.ts, 7, 68)) + + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => +>func : Symbol(func, Decl(declarationEmitPromise.ts, 8, 7)) +>T : Symbol(T, Decl(declarationEmitPromise.ts, 8, 16)) +>f : Symbol(f, Decl(declarationEmitPromise.ts, 8, 19)) +>a : Symbol(a, Decl(declarationEmitPromise.ts, 8, 23)) +>A : Symbol(A, Decl(declarationEmitPromise.ts, 5, 37)) +>b : Symbol(b, Decl(declarationEmitPromise.ts, 8, 28)) +>B : Symbol(B, Decl(declarationEmitPromise.ts, 5, 39)) +>c : Symbol(c, Decl(declarationEmitPromise.ts, 8, 35)) +>C : Symbol(C, Decl(declarationEmitPromise.ts, 5, 42)) +>d : Symbol(d, Decl(declarationEmitPromise.ts, 8, 42)) +>D : Symbol(D, Decl(declarationEmitPromise.ts, 5, 45)) +>e : Symbol(e, Decl(declarationEmitPromise.ts, 8, 49)) +>E : Symbol(E, Decl(declarationEmitPromise.ts, 5, 48)) +>T : Symbol(T, Decl(declarationEmitPromise.ts, 8, 16)) +>T : Symbol(T, Decl(declarationEmitPromise.ts, 8, 16)) + + f.apply(this, result); +>f.apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>f : Symbol(f, Decl(declarationEmitPromise.ts, 8, 19)) +>apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>result : Symbol(result, Decl(declarationEmitPromise.ts, 7, 7)) + + let rfunc: typeof func & {} = func as any; // <- This is the only difference +>rfunc : Symbol(rfunc, Decl(declarationEmitPromise.ts, 10, 7)) +>func : Symbol(func, Decl(declarationEmitPromise.ts, 8, 7)) +>func : Symbol(func, Decl(declarationEmitPromise.ts, 8, 7)) + + return rfunc +>rfunc : Symbol(rfunc, Decl(declarationEmitPromise.ts, 10, 7)) +} + +export async function runSampleBreaks( +>runSampleBreaks : Symbol(runSampleBreaks, Decl(declarationEmitPromise.ts, 12, 1)) +>A : Symbol(A, Decl(declarationEmitPromise.ts, 14, 38)) +>B : Symbol(B, Decl(declarationEmitPromise.ts, 14, 40)) +>C : Symbol(C, Decl(declarationEmitPromise.ts, 14, 43)) +>D : Symbol(D, Decl(declarationEmitPromise.ts, 14, 46)) +>E : Symbol(E, Decl(declarationEmitPromise.ts, 14, 49)) + + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { +>a : Symbol(a, Decl(declarationEmitPromise.ts, 14, 53)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>A : Symbol(A, Decl(declarationEmitPromise.ts, 14, 38)) +>b : Symbol(b, Decl(declarationEmitPromise.ts, 15, 19)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>B : Symbol(B, Decl(declarationEmitPromise.ts, 14, 40)) +>c : Symbol(c, Decl(declarationEmitPromise.ts, 15, 36)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>C : Symbol(C, Decl(declarationEmitPromise.ts, 14, 43)) +>d : Symbol(d, Decl(declarationEmitPromise.ts, 15, 53)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>D : Symbol(D, Decl(declarationEmitPromise.ts, 14, 46)) +>e : Symbol(e, Decl(declarationEmitPromise.ts, 15, 70)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>E : Symbol(E, Decl(declarationEmitPromise.ts, 14, 49)) + + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); +>result : Symbol(result, Decl(declarationEmitPromise.ts, 16, 7)) +>bluebird.all : Symbol(bluebird.all, Decl(declarationEmitPromise.ts, 1, 26)) +>bluebird : Symbol(bluebird, Decl(declarationEmitPromise.ts, 0, 0)) +>all : Symbol(bluebird.all, Decl(declarationEmitPromise.ts, 1, 26)) +>[a, b, c, d, e].filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(declarationEmitPromise.ts, 14, 53)) +>b : Symbol(b, Decl(declarationEmitPromise.ts, 15, 19)) +>c : Symbol(c, Decl(declarationEmitPromise.ts, 15, 36)) +>d : Symbol(d, Decl(declarationEmitPromise.ts, 15, 53)) +>e : Symbol(e, Decl(declarationEmitPromise.ts, 15, 70)) +>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --)) +>el : Symbol(el, Decl(declarationEmitPromise.ts, 16, 68)) +>el : Symbol(el, Decl(declarationEmitPromise.ts, 16, 68)) + + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => +>func : Symbol(func, Decl(declarationEmitPromise.ts, 17, 7)) +>T : Symbol(T, Decl(declarationEmitPromise.ts, 17, 16)) +>f : Symbol(f, Decl(declarationEmitPromise.ts, 17, 19)) +>a : Symbol(a, Decl(declarationEmitPromise.ts, 17, 23)) +>A : Symbol(A, Decl(declarationEmitPromise.ts, 14, 38)) +>b : Symbol(b, Decl(declarationEmitPromise.ts, 17, 28)) +>B : Symbol(B, Decl(declarationEmitPromise.ts, 14, 40)) +>c : Symbol(c, Decl(declarationEmitPromise.ts, 17, 35)) +>C : Symbol(C, Decl(declarationEmitPromise.ts, 14, 43)) +>d : Symbol(d, Decl(declarationEmitPromise.ts, 17, 42)) +>D : Symbol(D, Decl(declarationEmitPromise.ts, 14, 46)) +>e : Symbol(e, Decl(declarationEmitPromise.ts, 17, 49)) +>E : Symbol(E, Decl(declarationEmitPromise.ts, 14, 49)) +>T : Symbol(T, Decl(declarationEmitPromise.ts, 17, 16)) +>T : Symbol(T, Decl(declarationEmitPromise.ts, 17, 16)) + + f.apply(this, result); +>f.apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>f : Symbol(f, Decl(declarationEmitPromise.ts, 17, 19)) +>apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>result : Symbol(result, Decl(declarationEmitPromise.ts, 16, 7)) + + let rfunc: typeof func = func as any; // <- This is the only difference +>rfunc : Symbol(rfunc, Decl(declarationEmitPromise.ts, 19, 7)) +>func : Symbol(func, Decl(declarationEmitPromise.ts, 17, 7)) +>func : Symbol(func, Decl(declarationEmitPromise.ts, 17, 7)) + + return rfunc +>rfunc : Symbol(rfunc, Decl(declarationEmitPromise.ts, 19, 7)) +} diff --git a/tests/baselines/reference/declarationEmitPromise.types b/tests/baselines/reference/declarationEmitPromise.types new file mode 100644 index 00000000000..c423d5c68f7 --- /dev/null +++ b/tests/baselines/reference/declarationEmitPromise.types @@ -0,0 +1,181 @@ +=== tests/cases/compiler/declarationEmitPromise.ts === + +export class bluebird { +>bluebird : bluebird +>T : T + + static all: Array>; +>all : bluebird[] +>Array : T[] +>bluebird : bluebird +} + +export async function runSampleWorks( +>runSampleWorks : (a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) => Promise<((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}> +>A : A +>B : B +>C : C +>D : D +>E : E + + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { +>a : bluebird +>bluebird : bluebird +>A : A +>b : bluebird +>bluebird : bluebird +>B : B +>c : bluebird +>bluebird : bluebird +>C : C +>d : bluebird +>bluebird : bluebird +>D : D +>e : bluebird +>bluebird : bluebird +>E : E + + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); +>result : any +>await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)) : any +>(bluebird.all as any)([a, b, c, d, e].filter(el => !!el)) : any +>(bluebird.all as any) : any +>bluebird.all as any : any +>bluebird.all : bluebird[] +>bluebird : typeof bluebird +>all : bluebird[] +>[a, b, c, d, e].filter(el => !!el) : bluebird[] +>[a, b, c, d, e].filter : (callbackfn: (value: bluebird, index: number, array: bluebird[]) => any, thisArg?: any) => bluebird[] +>[a, b, c, d, e] : bluebird[] +>a : bluebird +>b : bluebird +>c : bluebird +>d : bluebird +>e : bluebird +>filter : (callbackfn: (value: bluebird, index: number, array: bluebird[]) => any, thisArg?: any) => bluebird[] +>el => !!el : (el: bluebird) => boolean +>el : bluebird +>!!el : boolean +>!el : boolean +>el : bluebird + + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => +>func : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => f.apply(this, result) : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +>T : T +>f : (a: A, b?: B, c?: C, d?: D, e?: E) => T +>a : A +>A : A +>b : B +>B : B +>c : C +>C : C +>d : D +>D : D +>e : E +>E : E +>T : T +>T : T + + f.apply(this, result); +>f.apply(this, result) : T +>f.apply : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, argArray?: any): U; (this: Function, thisArg: any, argArray?: any): any; } +>f : (a: A, b?: B, c?: C, d?: D, e?: E) => T +>apply : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, argArray?: any): U; (this: Function, thisArg: any, argArray?: any): any; } +>this : any +>result : any + + let rfunc: typeof func & {} = func as any; // <- This is the only difference +>rfunc : ((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {} +>func : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +>func as any : any +>func : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T + + return rfunc +>rfunc : ((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {} +} + +export async function runSampleBreaks( +>runSampleBreaks : (a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) => Promise<(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T> +>A : A +>B : B +>C : C +>D : D +>E : E + + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { +>a : bluebird +>bluebird : bluebird +>A : A +>b : bluebird +>bluebird : bluebird +>B : B +>c : bluebird +>bluebird : bluebird +>C : C +>d : bluebird +>bluebird : bluebird +>D : D +>e : bluebird +>bluebird : bluebird +>E : E + + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); +>result : any +>await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)) : any +>(bluebird.all as any)([a, b, c, d, e].filter(el => !!el)) : any +>(bluebird.all as any) : any +>bluebird.all as any : any +>bluebird.all : bluebird[] +>bluebird : typeof bluebird +>all : bluebird[] +>[a, b, c, d, e].filter(el => !!el) : bluebird[] +>[a, b, c, d, e].filter : (callbackfn: (value: bluebird, index: number, array: bluebird[]) => any, thisArg?: any) => bluebird[] +>[a, b, c, d, e] : bluebird[] +>a : bluebird +>b : bluebird +>c : bluebird +>d : bluebird +>e : bluebird +>filter : (callbackfn: (value: bluebird, index: number, array: bluebird[]) => any, thisArg?: any) => bluebird[] +>el => !!el : (el: bluebird) => boolean +>el : bluebird +>!!el : boolean +>!el : boolean +>el : bluebird + + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => +>func : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => f.apply(this, result) : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +>T : T +>f : (a: A, b?: B, c?: C, d?: D, e?: E) => T +>a : A +>A : A +>b : B +>B : B +>c : C +>C : C +>d : D +>D : D +>e : E +>E : E +>T : T +>T : T + + f.apply(this, result); +>f.apply(this, result) : T +>f.apply : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, argArray?: any): U; (this: Function, thisArg: any, argArray?: any): any; } +>f : (a: A, b?: B, c?: C, d?: D, e?: E) => T +>apply : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, argArray?: any): U; (this: Function, thisArg: any, argArray?: any): any; } +>this : any +>result : any + + let rfunc: typeof func = func as any; // <- This is the only difference +>rfunc : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +>func : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +>func as any : any +>func : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T + + return rfunc +>rfunc : (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T +} diff --git a/tests/cases/compiler/declarationEmitPromise.ts b/tests/cases/compiler/declarationEmitPromise.ts new file mode 100644 index 00000000000..2eff0b6c50c --- /dev/null +++ b/tests/cases/compiler/declarationEmitPromise.ts @@ -0,0 +1,25 @@ +// @declaration: true +// @module: commonjs +// @target: es6 + +export class bluebird { + static all: Array>; +} + +export async function runSampleWorks( + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => + f.apply(this, result); + let rfunc: typeof func & {} = func as any; // <- This is the only difference + return rfunc +} + +export async function runSampleBreaks( + a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) { + let result = await (bluebird.all as any)([a, b, c, d, e].filter(el => !!el)); + let func = (f: (a: A, b?: B, c?: C, d?: D, e?: E) => T): T => + f.apply(this, result); + let rfunc: typeof func = func as any; // <- This is the only difference + return rfunc +} \ No newline at end of file From b83dc88f9b9f0d874adea078a8c5efceb6841ab0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Apr 2016 13:51:40 -0700 Subject: [PATCH 068/110] Improve expression type caching to ensure consistent results --- src/compiler/checker.ts | 71 ++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1eeec55db8d..a7a875892d8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -180,7 +180,9 @@ namespace ts { let jsxElementClassType: Type; let deferredNodes: Node[]; - let inFlowCheck = false; + + let flowStackStart = 0; + let flowStackCount = 0; const tupleTypes: Map = {}; const unionTypes: Map = {}; @@ -195,6 +197,8 @@ namespace ts { const symbolLinks: SymbolLinks[] = []; const nodeLinks: NodeLinks[] = []; const flowTypeCaches: Map[] = []; + const flowStackNodes: FlowNode[] = []; + const flowStackCacheKeys: string[] = []; const potentialThisCollisions: Node[] = []; const awaitedTypeStack: number[] = []; @@ -7409,7 +7413,7 @@ namespace ts { function getTypeWithDefault(type: Type, defaultExpression: Expression) { if (defaultExpression) { - const defaultType = checkExpressionCached(defaultExpression); + const defaultType = checkExpression(defaultExpression); return getUnionType([getTypeWithFacts(type, TypeFacts.NEUndefined), defaultType]); } return type; @@ -7436,7 +7440,7 @@ namespace ts { function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { return node.parent.kind === SyntaxKind.ArrayLiteralExpression || node.parent.kind === SyntaxKind.PropertyAssignment ? getTypeWithDefault(getAssignedType(node), node.right) : - checkExpressionCached(node.right); + checkExpression(node.right); } function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { @@ -7487,9 +7491,17 @@ namespace ts { return getTypeWithDefault(type, node.initializer); } + function getTypeOfInitializer(node: Expression) { + // Return the cached type if one is available. If the type of the variable was inferred + // from its initializer, we'll already have cached the type. Otherwise we compute it now + // without caching such that transient types are reflected. + const links = getNodeLinks(node); + return links.resolvedType || checkExpression(node); + } + function getInitialTypeOfVariableDeclaration(node: VariableDeclaration) { if (node.initializer) { - return checkExpressionCached(node.initializer); + return getTypeOfInitializer(node.initializer); } if (node.parent.parent.kind === SyntaxKind.ForInStatement) { return stringType; @@ -7529,11 +7541,7 @@ namespace ts { function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) { let key: string; - const saveInFlowCheck = inFlowCheck; - inFlowCheck = true; - const result = reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : declaredType; - inFlowCheck = saveInFlowCheck; - return result; + return reference.flowNode ? getTypeAtFlowNode(reference.flowNode) : declaredType; function getTypeAtFlowNode(flow: FlowNode): Type { while (true) { @@ -7601,30 +7609,41 @@ namespace ts { if (!key) { key = getFlowCacheKey(reference); } - let type = cache[key]; - if (type) { - return type; + const cached = cache[key]; + if (cached) { + return cached; } - cache[key] = resolvingFlowType; - type = getTypeAtFlowNode(flow); - cache[key] = type !== resolvingFlowType ? type : undefined; - return type; + // Return undefined if we're already processing the given node. + for (let i = flowStackStart; i < flowStackCount; i++) { + if (flowStackNodes[i] === flow && flowStackCacheKeys[i] === key) { + return undefined; + } + } + // Record node and key on stack of nodes being processed. + flowStackNodes[flowStackCount] = flow; + flowStackCacheKeys[flowStackCount] = key; + flowStackCount++; + const type = getTypeAtFlowNode(flow); + flowStackCount--; + // Record the result only if the cache is still empty. If checkExpressionCached was called + // during processing it is possible we've already recorded a result. + return cache[key] || (cache[key] = type); } function getTypeAtFlowLabel(flow: FlowLabel) { const antecedentTypes: Type[] = []; for (const antecedent of flow.antecedents) { - const t = getTypeAtFlowNodeCached(antecedent); - if (t !== resolvingFlowType) { + const type = getTypeAtFlowNodeCached(antecedent); + if (type) { // If the type at a particular antecedent path is the declared type and the // reference is known to always be assigned (i.e. when declared and initial types // are the same), there is no reason to process more antecedents since the only // possible outcome is subtypes that will be removed in the final union type anyway. - if (t === declaredType && declaredType === initialType) { - return t; + if (type === declaredType && declaredType === initialType) { + return type; } - if (!contains(antecedentTypes, t)) { - antecedentTypes.push(t); + if (!contains(antecedentTypes, type)) { + antecedentTypes.push(type); } } } @@ -11107,7 +11126,7 @@ namespace ts { // If signature resolution originated in control flow type analysis (for example to compute the // assigned type in a flow assignment) we don't cache the result as it may be based on temporary // types from the control flow analysis. - links.resolvedSignature = inFlowCheck ? cached : result; + links.resolvedSignature = flowStackStart === flowStackCount ? result : cached; return result; } @@ -12246,7 +12265,13 @@ namespace ts { function checkExpressionCached(node: Expression, contextualMapper?: TypeMapper): Type { const links = getNodeLinks(node); if (!links.resolvedType) { + // When computing a type that we're going to cache, we need to ignore any ongoing control flow + // analysis because variables may have transient types in indeterminable states. Moving flowStackStart + // to the top of the stack ensures all transient types are computed from a known point. + const saveFlowStackStart = flowStackStart; + flowStackStart = flowStackCount; links.resolvedType = checkExpression(node, contextualMapper); + flowStackStart = saveFlowStackStart; } return links.resolvedType; } From 538e22a35eb515ade1fe0a944f305b8f0ae6b101 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Apr 2016 13:51:51 -0700 Subject: [PATCH 069/110] Adding tests --- .../controlFlow/controlFlowIterationErrors.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts b/tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts index a8a580150e8..2e54b335537 100644 --- a/tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts +++ b/tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts @@ -1,3 +1,5 @@ +// @noImplicitAny: true + let cond: boolean; function len(s: string) { @@ -46,3 +48,46 @@ function g2() { } x; } + +function asNumber(x: string | number): number { + return +x; +} + +function h1() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x = +x + 1; + x; + } +} + +function h2() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x = asNumber(x) + 1; + x; + } +} + +function h3() { + let x: string | number | boolean; + x = "0"; + while (cond) { + let y = asNumber(x); + x = y + 1; + x; + } +} + +function h4() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x; + let y = asNumber(x); + x = y + 1; + x; + } +} From b5104cbe69f9ac65114f7ee646487df80bdfedf6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Apr 2016 15:39:49 -0700 Subject: [PATCH 070/110] Accepting new baselines --- .../controlFlowIterationErrors.errors.txt | 70 ++++++++++++++-- .../reference/controlFlowIterationErrors.js | 82 +++++++++++++++++++ 2 files changed, 147 insertions(+), 5 deletions(-) diff --git a/tests/baselines/reference/controlFlowIterationErrors.errors.txt b/tests/baselines/reference/controlFlowIterationErrors.errors.txt index 748bf05dfb7..737a9e9557b 100644 --- a/tests/baselines/reference/controlFlowIterationErrors.errors.txt +++ b/tests/baselines/reference/controlFlowIterationErrors.errors.txt @@ -1,14 +1,21 @@ -tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(11,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(12,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(22,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(23,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(34,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(35,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(45,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(46,17): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(77,13): error TS7022: 'y' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(77,26): error TS2345: Argument of type 'string | number | boolean' is not assignable to parameter of type 'string | number'. + Type 'boolean' is not assignable to type 'string | number'. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(88,13): error TS7022: 'y' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. +tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(88,26): error TS2345: Argument of type 'string | number | boolean' is not assignable to parameter of type 'string | number'. + Type 'boolean' is not assignable to type 'string | number'. -==== tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts (4 errors) ==== +==== tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts (8 errors) ==== + let cond: boolean; function len(s: string) { @@ -69,4 +76,57 @@ tests/cases/conformance/controlFlow/controlFlowIterationErrors.ts(45,17): error } x; } + + function asNumber(x: string | number): number { + return +x; + } + + function h1() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x = +x + 1; + x; + } + } + + function h2() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x = asNumber(x) + 1; + x; + } + } + + function h3() { + let x: string | number | boolean; + x = "0"; + while (cond) { + let y = asNumber(x); + ~ +!!! error TS7022: 'y' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. + ~ +!!! error TS2345: Argument of type 'string | number | boolean' is not assignable to parameter of type 'string | number'. +!!! error TS2345: Type 'boolean' is not assignable to type 'string | number'. + x = y + 1; + x; + } + } + + function h4() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x; + let y = asNumber(x); + ~ +!!! error TS7022: 'y' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. + ~ +!!! error TS2345: Argument of type 'string | number | boolean' is not assignable to parameter of type 'string | number'. +!!! error TS2345: Type 'boolean' is not assignable to type 'string | number'. + x = y + 1; + x; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowIterationErrors.js b/tests/baselines/reference/controlFlowIterationErrors.js index 6c4a9a0b7e0..eed54cc53a7 100644 --- a/tests/baselines/reference/controlFlowIterationErrors.js +++ b/tests/baselines/reference/controlFlowIterationErrors.js @@ -1,4 +1,5 @@ //// [controlFlowIterationErrors.ts] + let cond: boolean; function len(s: string) { @@ -47,6 +48,49 @@ function g2() { } x; } + +function asNumber(x: string | number): number { + return +x; +} + +function h1() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x = +x + 1; + x; + } +} + +function h2() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x = asNumber(x) + 1; + x; + } +} + +function h3() { + let x: string | number | boolean; + x = "0"; + while (cond) { + let y = asNumber(x); + x = y + 1; + x; + } +} + +function h4() { + let x: string | number | boolean; + x = "0"; + while (cond) { + x; + let y = asNumber(x); + x = y + 1; + x; + } +} //// [controlFlowIterationErrors.js] @@ -90,3 +134,41 @@ function g2() { } x; } +function asNumber(x) { + return +x; +} +function h1() { + var x; + x = "0"; + while (cond) { + x = +x + 1; + x; + } +} +function h2() { + var x; + x = "0"; + while (cond) { + x = asNumber(x) + 1; + x; + } +} +function h3() { + var x; + x = "0"; + while (cond) { + var y = asNumber(x); + x = y + 1; + x; + } +} +function h4() { + var x; + x = "0"; + while (cond) { + x; + var y = asNumber(x); + x = y + 1; + x; + } +} From dc4871a12a82c22bd9e57874e837fefc824b3089 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 18 Apr 2016 15:44:40 -0700 Subject: [PATCH 071/110] Parenthesize the fn or constructor type with type parameter when writing it in type argument Fixes #8105 --- src/compiler/checker.ts | 24 ++++++-- src/compiler/types.ts | 1 + .../reference/declarationEmitPromise.js | 61 +------------------ .../reference/declarationEmitPromise.types | 2 +- .../specializedLambdaTypeArguments.types | 2 +- 5 files changed, 24 insertions(+), 66 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e989c8c8a04..9d101aab909 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1990,7 +1990,7 @@ namespace ts { } if (pos < end) { writePunctuation(writer, SyntaxKind.LessThanToken); - writeType(typeArguments[pos], TypeFormatFlags.None); + writeType(typeArguments[pos], TypeFormatFlags.InFirstTypeArgument); pos++; while (pos < end) { writePunctuation(writer, SyntaxKind.CommaToken); @@ -2143,6 +2143,19 @@ namespace ts { } } + function shouldAddParenthesisAroundFunctionType(callSignature: Signature, flags: TypeFormatFlags) { + if (flags & TypeFormatFlags.InElementType) { + return true; + } + else if (flags & TypeFormatFlags.InFirstTypeArgument) { + // Add parenthesis around function type for the first type argument to avoid ambiguity + const typeParameters = callSignature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) ? + callSignature.target.typeParameters : callSignature.typeParameters; + return typeParameters && typeParameters.length !== 0; + } + return false; + } + function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) { const resolved = resolveStructuredTypeMembers(type); if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) { @@ -2153,11 +2166,12 @@ namespace ts { } if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { - if (flags & TypeFormatFlags.InElementType) { + const parenthesizeSignature = shouldAddParenthesisAroundFunctionType(resolved.callSignatures[0], flags); + if (parenthesizeSignature) { writePunctuation(writer, SyntaxKind.OpenParenToken); } buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack); - if (flags & TypeFormatFlags.InElementType) { + if (parenthesizeSignature) { writePunctuation(writer, SyntaxKind.CloseParenToken); } return; @@ -2317,12 +2331,14 @@ namespace ts { function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { if (typeParameters && typeParameters.length) { writePunctuation(writer, SyntaxKind.LessThanToken); + let flags = TypeFormatFlags.InFirstTypeArgument; for (let i = 0; i < typeParameters.length; i++) { if (i > 0) { writePunctuation(writer, SyntaxKind.CommaToken); writeSpace(writer); + flags = TypeFormatFlags.None; } - buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, TypeFormatFlags.None); + buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, flags); } writePunctuation(writer, SyntaxKind.GreaterThanToken); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 718be453b09..c39a4b10cbf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1820,6 +1820,7 @@ namespace ts { WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature InElementType = 0x00000040, // Writing an array or union element type UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type) + InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type } export const enum SymbolFormatFlags { diff --git a/tests/baselines/reference/declarationEmitPromise.js b/tests/baselines/reference/declarationEmitPromise.js index 7387623dfe2..a4bbdd74dde 100644 --- a/tests/baselines/reference/declarationEmitPromise.js +++ b/tests/baselines/reference/declarationEmitPromise.js @@ -60,63 +60,4 @@ export declare class bluebird { static all: Array>; } export declare function runSampleWorks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>; -export declare function runSampleBreaks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>; - - -//// [DtsFileErrors] - - -tests/cases/compiler/declarationEmitPromise.d.ts(5,141): error TS2314: Generic type 'Promise' requires 1 type argument(s). -tests/cases/compiler/declarationEmitPromise.d.ts(5,148): error TS1144: '{' or ';' expected. -tests/cases/compiler/declarationEmitPromise.d.ts(5,150): error TS2304: Cannot find name 'T'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,153): error TS2304: Cannot find name 'f'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,154): error TS1005: ')' expected. -tests/cases/compiler/declarationEmitPromise.d.ts(5,160): error TS2304: Cannot find name 'A'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,167): error TS2304: Cannot find name 'B'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,174): error TS2304: Cannot find name 'C'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,181): error TS2304: Cannot find name 'D'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,188): error TS2304: Cannot find name 'E'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,194): error TS2304: Cannot find name 'T'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,195): error TS1005: ';' expected. -tests/cases/compiler/declarationEmitPromise.d.ts(5,197): error TS1128: Declaration or statement expected. -tests/cases/compiler/declarationEmitPromise.d.ts(5,200): error TS2304: Cannot find name 'T'. -tests/cases/compiler/declarationEmitPromise.d.ts(5,202): error TS1109: Expression expected. - - -==== tests/cases/compiler/declarationEmitPromise.d.ts (15 errors) ==== - export declare class bluebird { - static all: Array>; - } - export declare function runSampleWorks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>; - export declare function runSampleBreaks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>; - ~~~~~~~ -!!! error TS2314: Generic type 'Promise' requires 1 type argument(s). - ~~ -!!! error TS1144: '{' or ';' expected. - ~ -!!! error TS2304: Cannot find name 'T'. - ~ -!!! error TS2304: Cannot find name 'f'. - ~ -!!! error TS1005: ')' expected. - ~ -!!! error TS2304: Cannot find name 'A'. - ~ -!!! error TS2304: Cannot find name 'B'. - ~ -!!! error TS2304: Cannot find name 'C'. - ~ -!!! error TS2304: Cannot find name 'D'. - ~ -!!! error TS2304: Cannot find name 'E'. - ~ -!!! error TS2304: Cannot find name 'T'. - ~ -!!! error TS1005: ';' expected. - ~~ -!!! error TS1128: Declaration or statement expected. - ~ -!!! error TS2304: Cannot find name 'T'. - ~ -!!! error TS1109: Expression expected. - \ No newline at end of file +export declare function runSampleBreaks(a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird): Promise<((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>; diff --git a/tests/baselines/reference/declarationEmitPromise.types b/tests/baselines/reference/declarationEmitPromise.types index c423d5c68f7..0306c72762b 100644 --- a/tests/baselines/reference/declarationEmitPromise.types +++ b/tests/baselines/reference/declarationEmitPromise.types @@ -96,7 +96,7 @@ export async function runSampleWorks( } export async function runSampleBreaks( ->runSampleBreaks : (a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) => Promise<(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T> +>runSampleBreaks : (a: bluebird, b?: bluebird, c?: bluebird, d?: bluebird, e?: bluebird) => Promise<((f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)> >A : A >B : B >C : C diff --git a/tests/baselines/reference/specializedLambdaTypeArguments.types b/tests/baselines/reference/specializedLambdaTypeArguments.types index 3eb2fbc959e..b10da421044 100644 --- a/tests/baselines/reference/specializedLambdaTypeArguments.types +++ b/tests/baselines/reference/specializedLambdaTypeArguments.types @@ -4,7 +4,7 @@ class X { >A : A prop: X< () => Tany >; ->prop : X<() => Tany> +>prop : X<(() => Tany)> >X : X >Tany : Tany >Tany : Tany From 06f54b91242741276347f15f4e35d4403a287f52 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 18 Apr 2016 15:47:03 -0700 Subject: [PATCH 072/110] Adding another test case to handle more generic scenarios --- ...mitFirstTypeArgumentGenericFunctionType.js | 155 ++++++++++++++++++ ...rstTypeArgumentGenericFunctionType.symbols | 81 +++++++++ ...FirstTypeArgumentGenericFunctionType.types | 81 +++++++++ ...mitFirstTypeArgumentGenericFunctionType.ts | 26 +++ 4 files changed, 343 insertions(+) create mode 100644 tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js create mode 100644 tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.symbols create mode 100644 tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.types create mode 100644 tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.ts diff --git a/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js new file mode 100644 index 00000000000..2748b57933b --- /dev/null +++ b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js @@ -0,0 +1,155 @@ +//// [declarationEmitFirstTypeArgumentGenericFunctionType.ts] + +class X { +} +var prop11: X< () => Tany >; // spaces before the first type argument +var prop12: X<(() => Tany)>; // spaces before the first type argument +function f1() { // Inferred return type + return prop11; +} +function f2() { // Inferred return type + return prop12; +} +function f3(): X< () => Tany> { // written with space before type argument + return prop11; +} +function f4(): X<(() => Tany)> { // written type with parenthesis + return prop12; +} +class Y { +} +var prop2: Y() => Tany>; // No space after second type argument +var prop2: Y() => Tany>; // space after second type argument +var prop3: Y< () => Tany, () => Tany>; // space before first type argument +var prop4: Y<(() => Tany), () => Tany>; // parenthesized first type argument + + +//// [declarationEmitFirstTypeArgumentGenericFunctionType.js] +class X { +} +var prop11; // spaces before the first type argument +var prop12; // spaces before the first type argument +function f1() { + return prop11; +} +function f2() { + return prop12; +} +function f3() { + return prop11; +} +function f4() { + return prop12; +} +class Y { +} +var prop2; // No space after second type argument +var prop2; // space after second type argument +var prop3; // space before first type argument +var prop4; // parenthesized first type argument + + +//// [declarationEmitFirstTypeArgumentGenericFunctionType.d.ts] +declare class X { +} +declare var prop11: X<() => Tany>; +declare var prop12: X<(() => Tany)>; +declare function f1(): X<(() => Tany)>; +declare function f2(): X<(() => Tany)>; +declare function f3(): X<() => Tany>; +declare function f4(): X<(() => Tany)>; +declare class Y { +} +declare var prop2: Y() => Tany>; +declare var prop2: Y() => Tany>; +declare var prop3: Y<() => Tany, () => Tany>; +declare var prop4: Y<(() => Tany), () => Tany>; + + +//// [DtsFileErrors] + + +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,21): error TS2314: Generic type 'X' requires 1 type argument(s). +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,22): error TS1005: '=' expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,24): error TS2304: Cannot find name 'Tany'. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,30): error TS1109: Expression expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,32): error TS1005: ';' expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,35): error TS2304: Cannot find name 'Tany'. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,40): error TS1109: Expression expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,24): error TS2314: Generic type 'X' requires 1 type argument(s). +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,25): error TS1144: '{' or ';' expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,27): error TS2304: Cannot find name 'Tany'. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,33): error TS1109: Expression expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,35): error TS1005: ';' expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,38): error TS2304: Cannot find name 'Tany'. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,43): error TS1109: Expression expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,20): error TS2314: Generic type 'Y' requires 2 type argument(s). +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,21): error TS1005: '=' expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,23): error TS2304: Cannot find name 'Tany'. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,29): error TS1109: Expression expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,31): error TS1005: ';' expected. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,34): error TS2304: Cannot find name 'Tany'. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,52): error TS2304: Cannot find name 'Tany'. +tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,57): error TS1109: Expression expected. + + +==== tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts (22 errors) ==== + declare class X { + } + declare var prop11: X<() => Tany>; + ~ +!!! error TS2314: Generic type 'X' requires 1 type argument(s). + ~~ +!!! error TS1005: '=' expected. + ~~~~ +!!! error TS2304: Cannot find name 'Tany'. + ~ +!!! error TS1109: Expression expected. + ~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'Tany'. + ~ +!!! error TS1109: Expression expected. + declare var prop12: X<(() => Tany)>; + declare function f1(): X<(() => Tany)>; + declare function f2(): X<(() => Tany)>; + declare function f3(): X<() => Tany>; + ~ +!!! error TS2314: Generic type 'X' requires 1 type argument(s). + ~~ +!!! error TS1144: '{' or ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'Tany'. + ~ +!!! error TS1109: Expression expected. + ~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'Tany'. + ~ +!!! error TS1109: Expression expected. + declare function f4(): X<(() => Tany)>; + declare class Y { + } + declare var prop2: Y() => Tany>; + declare var prop2: Y() => Tany>; + declare var prop3: Y<() => Tany, () => Tany>; + ~ +!!! error TS2314: Generic type 'Y' requires 2 type argument(s). + ~~ +!!! error TS1005: '=' expected. + ~~~~ +!!! error TS2304: Cannot find name 'Tany'. + ~ +!!! error TS1109: Expression expected. + ~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'Tany'. + ~~~~ +!!! error TS2304: Cannot find name 'Tany'. + ~ +!!! error TS1109: Expression expected. + declare var prop4: Y<(() => Tany), () => Tany>; + \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.symbols b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.symbols new file mode 100644 index 00000000000..ebbc2b764b0 --- /dev/null +++ b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.symbols @@ -0,0 +1,81 @@ +=== tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.ts === + +class X { +>X : Symbol(X, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 0, 0)) +>A : Symbol(A, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 1, 8)) +} +var prop11: X< () => Tany >; // spaces before the first type argument +>prop11 : Symbol(prop11, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 3, 3)) +>X : Symbol(X, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 0, 0)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 3, 16)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 3, 16)) + +var prop12: X<(() => Tany)>; // spaces before the first type argument +>prop12 : Symbol(prop12, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 4, 3)) +>X : Symbol(X, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 0, 0)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 4, 16)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 4, 16)) + +function f1() { // Inferred return type +>f1 : Symbol(f1, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 4, 34)) + + return prop11; +>prop11 : Symbol(prop11, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 3, 3)) +} +function f2() { // Inferred return type +>f2 : Symbol(f2, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 7, 1)) + + return prop12; +>prop12 : Symbol(prop12, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 4, 3)) +} +function f3(): X< () => Tany> { // written with space before type argument +>f3 : Symbol(f3, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 10, 1)) +>X : Symbol(X, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 0, 0)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 11, 19)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 11, 19)) + + return prop11; +>prop11 : Symbol(prop11, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 3, 3)) +} +function f4(): X<(() => Tany)> { // written type with parenthesis +>f4 : Symbol(f4, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 13, 1)) +>X : Symbol(X, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 0, 0)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 14, 19)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 14, 19)) + + return prop12; +>prop12 : Symbol(prop12, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 4, 3)) +} +class Y { +>Y : Symbol(Y, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 16, 1)) +>A : Symbol(A, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 17, 8)) +>B : Symbol(B, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 17, 10)) +} +var prop2: Y() => Tany>; // No space after second type argument +>prop2 : Symbol(prop2, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 19, 3), Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 20, 3)) +>Y : Symbol(Y, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 16, 1)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 19, 24)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 19, 24)) + +var prop2: Y() => Tany>; // space after second type argument +>prop2 : Symbol(prop2, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 19, 3), Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 20, 3)) +>Y : Symbol(Y, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 16, 1)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 20, 24)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 20, 24)) + +var prop3: Y< () => Tany, () => Tany>; // space before first type argument +>prop3 : Symbol(prop3, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 21, 3)) +>Y : Symbol(Y, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 16, 1)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 21, 15)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 21, 15)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 21, 33)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 21, 33)) + +var prop4: Y<(() => Tany), () => Tany>; // parenthesized first type argument +>prop4 : Symbol(prop4, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 22, 3)) +>Y : Symbol(Y, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 16, 1)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 22, 15)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 22, 15)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 22, 34)) +>Tany : Symbol(Tany, Decl(declarationEmitFirstTypeArgumentGenericFunctionType.ts, 22, 34)) + diff --git a/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.types b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.types new file mode 100644 index 00000000000..4dd6ecba987 --- /dev/null +++ b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.types @@ -0,0 +1,81 @@ +=== tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.ts === + +class X { +>X : X +>A : A +} +var prop11: X< () => Tany >; // spaces before the first type argument +>prop11 : X<(() => Tany)> +>X : X +>Tany : Tany +>Tany : Tany + +var prop12: X<(() => Tany)>; // spaces before the first type argument +>prop12 : X<(() => Tany)> +>X : X +>Tany : Tany +>Tany : Tany + +function f1() { // Inferred return type +>f1 : () => X<(() => Tany)> + + return prop11; +>prop11 : X<(() => Tany)> +} +function f2() { // Inferred return type +>f2 : () => X<(() => Tany)> + + return prop12; +>prop12 : X<(() => Tany)> +} +function f3(): X< () => Tany> { // written with space before type argument +>f3 : () => X<(() => Tany)> +>X : X +>Tany : Tany +>Tany : Tany + + return prop11; +>prop11 : X<(() => Tany)> +} +function f4(): X<(() => Tany)> { // written type with parenthesis +>f4 : () => X<(() => Tany)> +>X : X +>Tany : Tany +>Tany : Tany + + return prop12; +>prop12 : X<(() => Tany)> +} +class Y { +>Y : Y +>A : A +>B : B +} +var prop2: Y() => Tany>; // No space after second type argument +>prop2 : Y() => Tany> +>Y : Y +>Tany : Tany +>Tany : Tany + +var prop2: Y() => Tany>; // space after second type argument +>prop2 : Y() => Tany> +>Y : Y +>Tany : Tany +>Tany : Tany + +var prop3: Y< () => Tany, () => Tany>; // space before first type argument +>prop3 : Y<(() => Tany), () => Tany> +>Y : Y +>Tany : Tany +>Tany : Tany +>Tany : Tany +>Tany : Tany + +var prop4: Y<(() => Tany), () => Tany>; // parenthesized first type argument +>prop4 : Y<(() => Tany), () => Tany> +>Y : Y +>Tany : Tany +>Tany : Tany +>Tany : Tany +>Tany : Tany + diff --git a/tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.ts b/tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.ts new file mode 100644 index 00000000000..3c5100d0772 --- /dev/null +++ b/tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.ts @@ -0,0 +1,26 @@ +// @declaration: true +// @module: commonjs +// @target: es6 + +class X { +} +var prop11: X< () => Tany >; // spaces before the first type argument +var prop12: X<(() => Tany)>; // spaces before the first type argument +function f1() { // Inferred return type + return prop11; +} +function f2() { // Inferred return type + return prop12; +} +function f3(): X< () => Tany> { // written with space before type argument + return prop11; +} +function f4(): X<(() => Tany)> { // written type with parenthesis + return prop12; +} +class Y { +} +var prop2: Y() => Tany>; // No space after second type argument +var prop2: Y() => Tany>; // space after second type argument +var prop3: Y< () => Tany, () => Tany>; // space before first type argument +var prop4: Y<(() => Tany), () => Tany>; // parenthesized first type argument From 685900c2a344ca8f41d23588737a877e6f042830 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 18 Apr 2016 16:08:52 -0700 Subject: [PATCH 073/110] Fix declaration emit when first generic function type in type argument position specified using space --- src/compiler/declarationEmitter.ts | 14 +++ ...mitFirstTypeArgumentGenericFunctionType.js | 95 +------------------ 2 files changed, 17 insertions(+), 92 deletions(-) diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 38df2e45d48..58ce2286627 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1377,6 +1377,7 @@ namespace ts { function emitSignatureDeclaration(node: SignatureDeclaration) { const prevEnclosingDeclaration = enclosingDeclaration; enclosingDeclaration = node; + let closeParenthesizedFunctionType = false; if (node.kind === SyntaxKind.IndexSignature) { // Index signature can have readonly modifier @@ -1388,6 +1389,16 @@ namespace ts { if (node.kind === SyntaxKind.ConstructSignature || node.kind === SyntaxKind.ConstructorType) { write("new "); } + else if (node.kind === SyntaxKind.FunctionType) { + const currentOutput = writer.getText(); + // Do not generate incorrect type when function type with type parameters is type argument + // This could happen if user used space between two '<' making it error free + // e.g var x: A< (a: Tany)=>Tany>; + if (node.typeParameters && currentOutput.charAt(currentOutput.length - 1) === "<") { + closeParenthesizedFunctionType = true; + write("("); + } + } emitTypeParameters(node.typeParameters); write("("); } @@ -1421,6 +1432,9 @@ namespace ts { write(";"); writeLine(); } + else if (closeParenthesizedFunctionType) { + write(")"); + } function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; diff --git a/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js index 2748b57933b..b2bca641a5a 100644 --- a/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js +++ b/tests/baselines/reference/declarationEmitFirstTypeArgumentGenericFunctionType.js @@ -52,104 +52,15 @@ var prop4; // parenthesized first type argument //// [declarationEmitFirstTypeArgumentGenericFunctionType.d.ts] declare class X { } -declare var prop11: X<() => Tany>; +declare var prop11: X<(() => Tany)>; declare var prop12: X<(() => Tany)>; declare function f1(): X<(() => Tany)>; declare function f2(): X<(() => Tany)>; -declare function f3(): X<() => Tany>; +declare function f3(): X<(() => Tany)>; declare function f4(): X<(() => Tany)>; declare class Y { } declare var prop2: Y() => Tany>; declare var prop2: Y() => Tany>; -declare var prop3: Y<() => Tany, () => Tany>; +declare var prop3: Y<(() => Tany), () => Tany>; declare var prop4: Y<(() => Tany), () => Tany>; - - -//// [DtsFileErrors] - - -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,21): error TS2314: Generic type 'X' requires 1 type argument(s). -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,22): error TS1005: '=' expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,24): error TS2304: Cannot find name 'Tany'. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,30): error TS1109: Expression expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,32): error TS1005: ';' expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,35): error TS2304: Cannot find name 'Tany'. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(3,40): error TS1109: Expression expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,24): error TS2314: Generic type 'X' requires 1 type argument(s). -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,25): error TS1144: '{' or ';' expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,27): error TS2304: Cannot find name 'Tany'. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,33): error TS1109: Expression expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,35): error TS1005: ';' expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,38): error TS2304: Cannot find name 'Tany'. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(7,43): error TS1109: Expression expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,20): error TS2314: Generic type 'Y' requires 2 type argument(s). -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,21): error TS1005: '=' expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,23): error TS2304: Cannot find name 'Tany'. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,29): error TS1109: Expression expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,31): error TS1005: ';' expected. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,34): error TS2304: Cannot find name 'Tany'. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,52): error TS2304: Cannot find name 'Tany'. -tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts(13,57): error TS1109: Expression expected. - - -==== tests/cases/compiler/declarationEmitFirstTypeArgumentGenericFunctionType.d.ts (22 errors) ==== - declare class X { - } - declare var prop11: X<() => Tany>; - ~ -!!! error TS2314: Generic type 'X' requires 1 type argument(s). - ~~ -!!! error TS1005: '=' expected. - ~~~~ -!!! error TS2304: Cannot find name 'Tany'. - ~ -!!! error TS1109: Expression expected. - ~~ -!!! error TS1005: ';' expected. - ~~~~ -!!! error TS2304: Cannot find name 'Tany'. - ~ -!!! error TS1109: Expression expected. - declare var prop12: X<(() => Tany)>; - declare function f1(): X<(() => Tany)>; - declare function f2(): X<(() => Tany)>; - declare function f3(): X<() => Tany>; - ~ -!!! error TS2314: Generic type 'X' requires 1 type argument(s). - ~~ -!!! error TS1144: '{' or ';' expected. - ~~~~ -!!! error TS2304: Cannot find name 'Tany'. - ~ -!!! error TS1109: Expression expected. - ~~ -!!! error TS1005: ';' expected. - ~~~~ -!!! error TS2304: Cannot find name 'Tany'. - ~ -!!! error TS1109: Expression expected. - declare function f4(): X<(() => Tany)>; - declare class Y { - } - declare var prop2: Y() => Tany>; - declare var prop2: Y() => Tany>; - declare var prop3: Y<() => Tany, () => Tany>; - ~ -!!! error TS2314: Generic type 'Y' requires 2 type argument(s). - ~~ -!!! error TS1005: '=' expected. - ~~~~ -!!! error TS2304: Cannot find name 'Tany'. - ~ -!!! error TS1109: Expression expected. - ~~ -!!! error TS1005: ';' expected. - ~~~~ -!!! error TS2304: Cannot find name 'Tany'. - ~~~~ -!!! error TS2304: Cannot find name 'Tany'. - ~ -!!! error TS1109: Expression expected. - declare var prop4: Y<(() => Tany), () => Tany>; - \ No newline at end of file From 19596deb7f0211102e2c655175947cf890b2d745 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Mon, 18 Apr 2016 16:20:45 -0700 Subject: [PATCH 074/110] remove extra deduplicate --- src/server/editorServices.ts | 5 ++++- src/server/session.ts | 11 ++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index e3bf97f2736..0393caa75bb 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -464,7 +464,10 @@ namespace ts.server { return copiedList; } - export function processEachProjectThenConcatSortDeduplicateResults(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) { + /** + * This helper funciton processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project. + */ + export function combineProjectOutput(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) { const result = projects.reduce((previous, current) => concatenate(previous, action(current)), []).sort(comparer); return projects.length > 1 ? deduplicate(result, areEqual) : result; } diff --git a/src/server/session.ts b/src/server/session.ts index d81b0ee286e..defdd577577 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -434,7 +434,7 @@ namespace ts.server { }; } - const fileSpans = processEachProjectThenConcatSortDeduplicateResults( + const fileSpans = combineProjectOutput( projects, (project: Project) => { const compilerService = project.compilerService; @@ -511,7 +511,7 @@ namespace ts.server { const nameSpan = nameInfo.textSpan; const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset; const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); - const refs = processEachProjectThenConcatSortDeduplicateResults( + const refs = combineProjectOutput( projects, (project: Project) => { const compilerService = project.compilerService; @@ -534,11 +534,12 @@ namespace ts.server { }; }); }, - compareFileStart + compareFileStart, + areReferencesResponseItemsForTheSameLocation ); return { - refs: deduplicate(refs, areReferencesResponseItemsForTheSameLocation), + refs, symbolName: nameText, symbolStartOffset: nameColStart, symbolDisplayString: displayString @@ -872,7 +873,7 @@ namespace ts.server { throw Errors.NoProject; } - const allNavToItems = processEachProjectThenConcatSortDeduplicateResults( + const allNavToItems = combineProjectOutput( projects, (project: Project) => { const compilerService = project.compilerService; From 87f55fa68351d39ac4b6d2654c8a079f7168d469 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Apr 2016 16:37:58 -0700 Subject: [PATCH 075/110] Only evaluate assigned type when declared type is a union type --- src/compiler/checker.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7a875892d8..977bb38ed5b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7343,9 +7343,9 @@ namespace ts { // Remove those constituent types of declaredType to which no constituent type of assignedType is assignable. // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, // we remove type string. - function getAssignmentReducedType(declaredType: Type, assignedType: Type) { + function getAssignmentReducedType(declaredType: UnionType, assignedType: Type) { if (declaredType !== assignedType && declaredType.flags & TypeFlags.Union) { - const reducedTypes = filter((declaredType).types, t => typeMaybeAssignableTo(assignedType, t)); + const reducedTypes = filter(declaredType.types, t => typeMaybeAssignableTo(assignedType, t)); if (reducedTypes.length) { return reducedTypes.length === 1 ? reducedTypes[0] : getUnionType(reducedTypes); } @@ -7573,16 +7573,22 @@ namespace ts { function getTypeAtFlowAssignment(flow: FlowAssignment) { const node = flow.node; + // Assignments only narrow the computed type if the declared type is a union type. Thus, we + // only need to evaluate the assigned type if the declared type is a union type. if ((node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) && reference.kind === SyntaxKind.Identifier && getResolvedSymbol(reference) === getSymbolOfNode(node)) { - return getAssignmentReducedType(declaredType, getInitialType(node)); + return declaredType.flags & TypeFlags.Union ? + getAssignmentReducedType(declaredType, getInitialType(node)) : + declaredType; } // If the node is not a variable declaration or binding element, it is an identifier // or a dotted name that is the target of an assignment. If we have a match, reduce // the declared type by the assigned type. if (isMatchingReference(reference, node)) { - return getAssignmentReducedType(declaredType, getAssignedType(node)); + return declaredType.flags & TypeFlags.Union ? + getAssignmentReducedType(declaredType, getAssignedType(node)) : + declaredType; } // We didn't have a direct match. However, if the reference is a dotted name, this // may be an assignment to a left hand part of the reference. For example, for a From 9defdde02f3c02d968db1345f4ad689129779e5e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Apr 2016 16:39:15 -0700 Subject: [PATCH 076/110] Accepting new baselines --- tests/baselines/reference/typeAssertions.errors.txt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/baselines/reference/typeAssertions.errors.txt b/tests/baselines/reference/typeAssertions.errors.txt index 0468eb23d22..e330c23d737 100644 --- a/tests/baselines/reference/typeAssertions.errors.txt +++ b/tests/baselines/reference/typeAssertions.errors.txt @@ -1,13 +1,10 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(5,5): error TS2346: Supplied parameters do not match any signature of call target. -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(31,12): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. Property 'p' is missing in type 'SomeOther'. -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(35,15): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. Property 'x' is missing in type 'SomeOther'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(37,13): error TS2352: Type 'SomeDerived' cannot be converted to type 'SomeOther'. Property 'q' is missing in type 'SomeDerived'. -tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. Property 'q' is missing in type 'SomeBase'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,5): error TS2304: Cannot find name 'numOrStr'. @@ -26,7 +23,7 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,44): err tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): error TS1005: ';' expected. -==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (21 errors) ==== +==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (18 errors) ==== // Function call whose argument is a 1 arg generic function call with explicit type arguments function fn1(t: T) { } function fn2(t: any) { } @@ -61,8 +58,6 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err someBase = someBase; someBase = someOther; // Error ~~~~~~~~~~~~~~~~~~~ -!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. - ~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. !!! error TS2352: Property 'p' is missing in type 'SomeOther'. @@ -70,8 +65,6 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err someDerived = someBase; someDerived = someOther; // Error ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. - ~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. !!! error TS2352: Property 'x' is missing in type 'SomeOther'. @@ -81,8 +74,6 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): err !!! error TS2352: Property 'q' is missing in type 'SomeDerived'. someOther = someBase; // Error ~~~~~~~~~~~~~~~~~~~ -!!! error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. - ~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. !!! error TS2352: Property 'q' is missing in type 'SomeBase'. someOther = someOther; From d28a4feeba6bc7eba7c924674e0bc64657259f31 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Apr 2016 16:58:22 -0700 Subject: [PATCH 077/110] typeof x === "function" type guards include Function interface --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 977bb38ed5b..d58ad9fbf9a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7366,7 +7366,7 @@ namespace ts { } if (flags & TypeFlags.ObjectType) { const resolved = resolveStructuredTypeMembers(type); - return resolved.callSignatures.length || resolved.constructSignatures.length ? + return resolved.callSignatures.length || resolved.constructSignatures.length || isTypeSubtypeOf(type, globalFunctionType) ? strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } From d48f6179f1f97700bb0071dae8b4aa21692f8b75 Mon Sep 17 00:00:00 2001 From: Yuichi Nukiyama Date: Tue, 19 Apr 2016 12:50:50 +0000 Subject: [PATCH 078/110] fix 8117 --- src/compiler/emitter.ts | 2 +- .../singleLineCommentInConciseArrowFunctionES3.js | 14 ++++++++++++++ ...gleLineCommentInConciseArrowFunctionES3.symbols | 8 ++++++++ ...ingleLineCommentInConciseArrowFunctionES3.types | 11 +++++++++++ .../singleLineCommentInConciseArrowFunctionES3.ts | 5 +++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.js create mode 100644 tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.symbols create mode 100644 tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.types create mode 100644 tests/cases/compiler/singleLineCommentInConciseArrowFunctionES3.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 254b8d7e61b..396f178cab2 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -7879,7 +7879,7 @@ const _super = (function (geti, seti) { node.parent && node.parent.kind === SyntaxKind.ArrowFunction && (node.parent).body === node && - compilerOptions.target <= ScriptTarget.ES5) { + languageVersion <= ScriptTarget.ES5) { return false; } diff --git a/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.js b/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.js new file mode 100644 index 00000000000..db4ab7950eb --- /dev/null +++ b/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.js @@ -0,0 +1,14 @@ +//// [singleLineCommentInConciseArrowFunctionES3.ts] +function test() { + return () => + // some comments here; + 123; +} + +//// [singleLineCommentInConciseArrowFunctionES3.js] +function test() { + return function () { + // some comments here; + return 123; + }; +} diff --git a/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.symbols b/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.symbols new file mode 100644 index 00000000000..cb53d292885 --- /dev/null +++ b/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/singleLineCommentInConciseArrowFunctionES3.ts === +function test() { +>test : Symbol(test, Decl(singleLineCommentInConciseArrowFunctionES3.ts, 0, 0)) + + return () => + // some comments here; + 123; +} diff --git a/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.types b/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.types new file mode 100644 index 00000000000..e8c449e7bb8 --- /dev/null +++ b/tests/baselines/reference/singleLineCommentInConciseArrowFunctionES3.types @@ -0,0 +1,11 @@ +=== tests/cases/compiler/singleLineCommentInConciseArrowFunctionES3.ts === +function test() { +>test : () => () => number + + return () => +>() => // some comments here; 123 : () => number + + // some comments here; + 123; +>123 : number +} diff --git a/tests/cases/compiler/singleLineCommentInConciseArrowFunctionES3.ts b/tests/cases/compiler/singleLineCommentInConciseArrowFunctionES3.ts new file mode 100644 index 00000000000..0538df1c2d0 --- /dev/null +++ b/tests/cases/compiler/singleLineCommentInConciseArrowFunctionES3.ts @@ -0,0 +1,5 @@ +function test() { + return () => + // some comments here; + 123; +} \ No newline at end of file From d735b7acbf790376d380a127f1de7950016b8b42 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Apr 2016 10:04:17 -0700 Subject: [PATCH 079/110] Variables from different source files default to their declared type --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d58ad9fbf9a..bab573c8b7f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7936,7 +7936,7 @@ namespace ts { const declaration = localOrExportSymbol.valueDeclaration; const defaultsToDeclaredType = !strictNullChecks || !declaration || declaration.kind === SyntaxKind.Parameter || isInAmbientContext(declaration) || - getContainingFunction(declaration) !== getContainingFunction(node); + getContainingFunctionOrSourceFile(declaration) !== getContainingFunctionOrSourceFile(node); if (defaultsToDeclaredType && !(type.flags & TypeFlags.Narrowable)) { return type; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 638c7a60aa1..2e51f6a1504 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -840,6 +840,15 @@ namespace ts { } } + export function getContainingFunctionOrSourceFile(node: Node): FunctionLikeDeclaration | SourceFile { + while (true) { + node = node.parent; + if (isFunctionLike(node) || node.kind === SyntaxKind.SourceFile) { + return node; + } + } + } + export function getContainingClass(node: Node): ClassLikeDeclaration { while (true) { node = node.parent; From c8bf6d821a5de7329ded94af1fa743068e85ace3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Apr 2016 10:14:02 -0700 Subject: [PATCH 080/110] Variables from different module declarations default to their declared type --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bab573c8b7f..4731046864e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7936,7 +7936,7 @@ namespace ts { const declaration = localOrExportSymbol.valueDeclaration; const defaultsToDeclaredType = !strictNullChecks || !declaration || declaration.kind === SyntaxKind.Parameter || isInAmbientContext(declaration) || - getContainingFunctionOrSourceFile(declaration) !== getContainingFunctionOrSourceFile(node); + getContainingFunctionOrModule(declaration) !== getContainingFunctionOrModule(node); if (defaultsToDeclaredType && !(type.flags & TypeFlags.Narrowable)) { return type; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2e51f6a1504..60b041d843c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -840,11 +840,11 @@ namespace ts { } } - export function getContainingFunctionOrSourceFile(node: Node): FunctionLikeDeclaration | SourceFile { + export function getContainingFunctionOrModule(node: Node): Node { while (true) { node = node.parent; - if (isFunctionLike(node) || node.kind === SyntaxKind.SourceFile) { - return node; + if (isFunctionLike(node) || node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile) { + return node; } } } From 445cb7935e6a8a46e9759bfce010f3dcd1e79ef0 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 19 Apr 2016 10:53:13 -0700 Subject: [PATCH 081/110] Filter library text from RWC output --- src/harness/rwcRunner.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 8c3b3c70a1f..39231435bf5 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -190,8 +190,9 @@ namespace RWC { if (compilerResult.errors.length === 0) { return null; } - - return Harness.Compiler.getErrorBaseline(inputFiles.concat(otherFiles), compilerResult.errors); + // Do not include the library in the baselines to avoid noise + const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName)); + return Harness.Compiler.getErrorBaseline(baselineFiles, compilerResult.errors); }, false, baselineOpts); }); From 9cc9a99f4f80b65f836ca7c16c62d3cca0537a64 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 19 Apr 2016 14:00:14 -0700 Subject: [PATCH 082/110] Fix #8130: Do not fail if the resources for the specified locale does not exisit --- src/compiler/tsc.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index c2199cf7345..cada0c3daf8 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -44,11 +44,9 @@ namespace ts { const territory = matchResult[3]; // First try the entire locale, then fall back to just language if that's all we have. - if (!trySetLanguageAndTerritory(language, territory, errors) && - !trySetLanguageAndTerritory(language, undefined, errors)) { - - errors.push(createCompilerDiagnostic(Diagnostics.Unsupported_locale_0, locale)); - return false; + // Either ways do not fail, and fallback to the English diagnostic strings. + if (!trySetLanguageAndTerritory(language, territory, errors)) { + trySetLanguageAndTerritory(language, undefined, errors) } return true; From 80df773c770729ef63e4bc5345fe03fc2fc18800 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 19 Apr 2016 14:16:43 -0700 Subject: [PATCH 083/110] fix formatting for lines that start with continuation of multiline comments --- src/services/formatting/formatting.ts | 17 ++++++++--------- .../formattingWithMultilineComments.ts | 9 +++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 tests/cases/fourslash/formattingWithMultilineComments.ts diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 066bcf7cda6..58e3ed1b356 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -728,25 +728,24 @@ namespace ts.formatting { dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container) : Constants.Unknown; + let indentNextTokenOrTrivia = true; if (currentTokenInfo.leadingTrivia) { let commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation, container); - let indentNextTokenOrTrivia = true; for (let triviaItem of currentTokenInfo.leadingTrivia) { - if (!rangeContainsRange(originalRange, triviaItem)) { - continue; - } - + const triviaInRange = rangeContainsRange(originalRange, triviaItem); switch (triviaItem.kind) { case SyntaxKind.MultiLineCommentTrivia: - indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia); + if (triviaInRange) { + indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia); + } indentNextTokenOrTrivia = false; break; case SyntaxKind.SingleLineCommentTrivia: - if (indentNextTokenOrTrivia) { + if (indentNextTokenOrTrivia && triviaInRange) { insertIndentation(triviaItem.pos, commentIndentation, /*lineAdded*/ false); - indentNextTokenOrTrivia = false; } + indentNextTokenOrTrivia = false; break; case SyntaxKind.NewLineTrivia: indentNextTokenOrTrivia = true; @@ -756,7 +755,7 @@ namespace ts.formatting { } // indent token only if is it is in target range and does not overlap with any error ranges - if (tokenIndentation !== Constants.Unknown) { + if (tokenIndentation !== Constants.Unknown && indentNextTokenOrTrivia) { insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded); lastIndentedLine = tokenStart.line; diff --git a/tests/cases/fourslash/formattingWithMultilineComments.ts b/tests/cases/fourslash/formattingWithMultilineComments.ts new file mode 100644 index 00000000000..04cdfbcf472 --- /dev/null +++ b/tests/cases/fourslash/formattingWithMultilineComments.ts @@ -0,0 +1,9 @@ +/// + +////f(/* +/////*2*/ */() => { /*1*/ }); + +goTo.marker("1"); +edit.insertLine(""); +goTo.marker("2"); +verify.currentLineContentIs(" */() => {"); \ No newline at end of file From c53612dfb6320ae57ec14a45bef25a8ed17d7a96 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 19 Apr 2016 14:23:38 -0700 Subject: [PATCH 084/110] Add missing semicolon --- src/compiler/tsc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index cada0c3daf8..2e40cfdc53c 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -46,7 +46,7 @@ namespace ts { // First try the entire locale, then fall back to just language if that's all we have. // Either ways do not fail, and fallback to the English diagnostic strings. if (!trySetLanguageAndTerritory(language, territory, errors)) { - trySetLanguageAndTerritory(language, undefined, errors) + trySetLanguageAndTerritory(language, undefined, errors); } return true; From cc58e2d7eb144f0b2ff89e6a6685fb4deaa24fde Mon Sep 17 00:00:00 2001 From: zhengbli Date: Tue, 19 Apr 2016 15:17:36 -0700 Subject: [PATCH 085/110] Use string literal type for script kind names --- src/harness/harnessLanguageService.ts | 2 +- src/server/client.ts | 2 +- src/server/protocol.d.ts | 4 ++-- src/server/session.ts | 8 ++++---- tests/cases/fourslash/server/openFileWithSyntaxKind.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index d74c2fdeb8e..8f1b0493a85 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -496,7 +496,7 @@ namespace Harness.LanguageService { this.client = client; } - openFile(fileName: string, content?: string, scriptKindName?: string): void { + openFile(fileName: string, content?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void { super.openFile(fileName, content, scriptKindName); this.client.openFile(fileName, content, scriptKindName); } diff --git a/src/server/client.ts b/src/server/client.ts index 35fb0b11fbe..bd5abbcfd77 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -120,7 +120,7 @@ namespace ts.server { return response; } - openFile(fileName: string, content?: string, scriptKindName?: string): void { + openFile(fileName: string, content?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void { var args: protocol.OpenRequestArgs = { file: fileName, fileContent: content, scriptKindName }; this.processRequest(CommandNames.Open, args); } diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index d6ff438a1c0..10cebb2ddb7 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -520,9 +520,9 @@ declare namespace ts.server.protocol { fileContent?: string; /** * Used to specify the script kind of the file explicitly. It could be one of the following: - * ".ts", ".js", ".tsx", ".jsx" + * "TS", "JS", "TSX", "JSX" */ - scriptKindName?: string; + scriptKindName?: "TS" | "JS" | "TSX" | "JSX"; } /** diff --git a/src/server/session.ts b/src/server/session.ts index 6dd74e8985b..6fe8ed7b075 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -969,16 +969,16 @@ namespace ts.server { const openArgs = request.arguments; let scriptKind: ScriptKind; switch (openArgs.scriptKindName) { - case ".ts": + case "TS": scriptKind = ScriptKind.TS; break; - case ".js": + case "JS": scriptKind = ScriptKind.JS; break; - case ".tsx": + case "TSX": scriptKind = ScriptKind.TSX; break; - case ".jsx": + case "JSX": scriptKind = ScriptKind.JSX; break; } diff --git a/tests/cases/fourslash/server/openFileWithSyntaxKind.ts b/tests/cases/fourslash/server/openFileWithSyntaxKind.ts index 006e5490b6f..dcb1e54999e 100644 --- a/tests/cases/fourslash/server/openFileWithSyntaxKind.ts +++ b/tests/cases/fourslash/server/openFileWithSyntaxKind.ts @@ -14,6 +14,6 @@ //// var t; //// t. -goTo.file("test.ts", /*content*/ undefined, ".js"); +goTo.file("test.ts", /*content*/ undefined, "JS"); goTo.eof(); verify.completionListContains("toExponential"); From ef4b6613f3e156985cdbdfc5447e651eabbc712f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 19 Apr 2016 15:43:12 -0700 Subject: [PATCH 086/110] Adding testcase for function with rest param defined in jsDoc comment Test case for #7749 --- ...jsFileCompilationRestParamJsDocFunction.js | 55 ++++++++++++ ...eCompilationRestParamJsDocFunction.symbols | 68 ++++++++++++++ ...ileCompilationRestParamJsDocFunction.types | 89 +++++++++++++++++++ ...jsFileCompilationRestParamJsDocFunction.ts | 27 ++++++ 4 files changed, 239 insertions(+) create mode 100644 tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js create mode 100644 tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.symbols create mode 100644 tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.types create mode 100644 tests/cases/compiler/jsFileCompilationRestParamJsDocFunction.ts diff --git a/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js new file mode 100644 index 00000000000..9e5c53fbe05 --- /dev/null +++ b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js @@ -0,0 +1,55 @@ +//// [_apply.js] + +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { + var length = args.length; + switch (length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); +} + +export default apply; + +//// [apply.js] +define("_apply", ["require", "exports"], function (require, exports) { + "use strict"; + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg) { + var args = []; + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + var length = args.length; + switch (length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + exports.__esModule = true; + exports["default"] = apply; +}); diff --git a/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.symbols b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.symbols new file mode 100644 index 00000000000..62e47c8a3c4 --- /dev/null +++ b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.symbols @@ -0,0 +1,68 @@ +=== tests/cases/compiler/_apply.js === + +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { +>apply : Symbol(apply, Decl(_apply.js, 0, 0)) +>func : Symbol(func, Decl(_apply.js, 11, 15)) +>thisArg : Symbol(thisArg, Decl(_apply.js, 11, 20)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) + + var length = args.length; +>length : Symbol(length, Decl(_apply.js, 12, 7)) +>args.length : Symbol(Array.length, Decl(lib.d.ts, --, --)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) +>length : Symbol(Array.length, Decl(lib.d.ts, --, --)) + + switch (length) { +>length : Symbol(length, Decl(_apply.js, 12, 7)) + + case 0: return func.call(thisArg); +>func.call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>func : Symbol(func, Decl(_apply.js, 11, 15)) +>call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(_apply.js, 11, 20)) + + case 1: return func.call(thisArg, args[0]); +>func.call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>func : Symbol(func, Decl(_apply.js, 11, 15)) +>call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(_apply.js, 11, 20)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) + + case 2: return func.call(thisArg, args[0], args[1]); +>func.call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>func : Symbol(func, Decl(_apply.js, 11, 15)) +>call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(_apply.js, 11, 20)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) + + case 3: return func.call(thisArg, args[0], args[1], args[2]); +>func.call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>func : Symbol(func, Decl(_apply.js, 11, 15)) +>call : Symbol(Function.call, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(_apply.js, 11, 20)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) + } + return func.apply(thisArg, args); +>func.apply : Symbol(Function.apply, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>func : Symbol(func, Decl(_apply.js, 11, 15)) +>apply : Symbol(Function.apply, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(_apply.js, 11, 20)) +>args : Symbol(args, Decl(_apply.js, 11, 29)) +} + +export default apply; +>apply : Symbol(apply, Decl(_apply.js, 0, 0)) + diff --git a/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.types b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.types new file mode 100644 index 00000000000..78d0fd1392b --- /dev/null +++ b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.types @@ -0,0 +1,89 @@ +=== tests/cases/compiler/_apply.js === + +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { +>apply : (func: Function, thisArg: any, ...args: any[]) => any +>func : Function +>thisArg : any +>args : any[] + + var length = args.length; +>length : number +>args.length : number +>args : any[] +>length : number + + switch (length) { +>length : number + + case 0: return func.call(thisArg); +>0 : number +>func.call(thisArg) : any +>func.call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>func : Function +>call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>thisArg : any + + case 1: return func.call(thisArg, args[0]); +>1 : number +>func.call(thisArg, args[0]) : any +>func.call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>func : Function +>call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>thisArg : any +>args[0] : any +>args : any[] +>0 : number + + case 2: return func.call(thisArg, args[0], args[1]); +>2 : number +>func.call(thisArg, args[0], args[1]) : any +>func.call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>func : Function +>call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>thisArg : any +>args[0] : any +>args : any[] +>0 : number +>args[1] : any +>args : any[] +>1 : number + + case 3: return func.call(thisArg, args[0], args[1], args[2]); +>3 : number +>func.call(thisArg, args[0], args[1], args[2]) : any +>func.call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>func : Function +>call : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, ...argArray: any[]): U; (this: Function, thisArg: any, ...argArray: any[]): any; } +>thisArg : any +>args[0] : any +>args : any[] +>0 : number +>args[1] : any +>args : any[] +>1 : number +>args[2] : any +>args : any[] +>2 : number + } + return func.apply(thisArg, args); +>func.apply(thisArg, args) : any +>func.apply : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, argArray?: any): U; (this: Function, thisArg: any, argArray?: any): any; } +>func : Function +>apply : { (this: (this: T, ...argArray: any[]) => U, thisArg: T, argArray?: any): U; (this: Function, thisArg: any, argArray?: any): any; } +>thisArg : any +>args : any[] +} + +export default apply; +>apply : (func: Function, thisArg: any, ...args: any[]) => any + diff --git a/tests/cases/compiler/jsFileCompilationRestParamJsDocFunction.ts b/tests/cases/compiler/jsFileCompilationRestParamJsDocFunction.ts new file mode 100644 index 00000000000..03ad2d1b2ff --- /dev/null +++ b/tests/cases/compiler/jsFileCompilationRestParamJsDocFunction.ts @@ -0,0 +1,27 @@ +// @allowJs: true +// @out: apply.js +// @module: amd + +// @filename: _apply.js +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { + var length = args.length; + switch (length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); +} + +export default apply; \ No newline at end of file From 950571b04960c65df8e94c867e719881db650c06 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 19 Apr 2016 14:54:53 -0700 Subject: [PATCH 087/110] do not validate module names in augmentations defined in ambient context --- src/compiler/checker.ts | 6 +++++- .../reference/moduleAugmentationInDependency.js | 13 +++++++++++++ .../moduleAugmentationInDependency.symbols | 8 ++++++++ .../moduleAugmentationInDependency.types | 8 ++++++++ .../moduleAugmentationInDependency2.errors.txt | 12 ++++++++++++ .../reference/moduleAugmentationInDependency2.js | 15 +++++++++++++++ .../privacyGloImportParseErrors.errors.txt | 5 +---- .../compiler/moduleAugmentationInDependency.ts | 7 +++++++ .../compiler/moduleAugmentationInDependency2.ts | 7 +++++++ 9 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/moduleAugmentationInDependency.js create mode 100644 tests/baselines/reference/moduleAugmentationInDependency.symbols create mode 100644 tests/baselines/reference/moduleAugmentationInDependency.types create mode 100644 tests/baselines/reference/moduleAugmentationInDependency2.errors.txt create mode 100644 tests/baselines/reference/moduleAugmentationInDependency2.js create mode 100644 tests/cases/compiler/moduleAugmentationInDependency.ts create mode 100644 tests/cases/compiler/moduleAugmentationInDependency2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9d101aab909..1075f152c3e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -398,7 +398,11 @@ namespace ts { } else { // find a module that about to be augmented - let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found); + // do not validate names of augmentations that are defined in ambient context + const moduleNotFoundError = !isInAmbientContext(moduleName.parent.parent) + ? Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found + : undefined; + let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError); if (!mainModule) { return; } diff --git a/tests/baselines/reference/moduleAugmentationInDependency.js b/tests/baselines/reference/moduleAugmentationInDependency.js new file mode 100644 index 00000000000..1c5995339c3 --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationInDependency.js @@ -0,0 +1,13 @@ +//// [tests/cases/compiler/moduleAugmentationInDependency.ts] //// + +//// [index.d.ts] +declare module "ext" { +} +export {}; + +//// [app.ts] +import "A" + +//// [app.js] +"use strict"; +require("A"); diff --git a/tests/baselines/reference/moduleAugmentationInDependency.symbols b/tests/baselines/reference/moduleAugmentationInDependency.symbols new file mode 100644 index 00000000000..82f1faedbf5 --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationInDependency.symbols @@ -0,0 +1,8 @@ +=== /node_modules/A/index.d.ts === +declare module "ext" { +No type information for this code.} +No type information for this code.export {}; +No type information for this code. +No type information for this code.=== /src/app.ts === +import "A" +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/moduleAugmentationInDependency.types b/tests/baselines/reference/moduleAugmentationInDependency.types new file mode 100644 index 00000000000..82f1faedbf5 --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationInDependency.types @@ -0,0 +1,8 @@ +=== /node_modules/A/index.d.ts === +declare module "ext" { +No type information for this code.} +No type information for this code.export {}; +No type information for this code. +No type information for this code.=== /src/app.ts === +import "A" +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/moduleAugmentationInDependency2.errors.txt b/tests/baselines/reference/moduleAugmentationInDependency2.errors.txt new file mode 100644 index 00000000000..eb53c5265b6 --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationInDependency2.errors.txt @@ -0,0 +1,12 @@ +/node_modules/A/index.ts(1,16): error TS2664: Invalid module name in augmentation, module 'ext' cannot be found. + + +==== /node_modules/A/index.ts (1 errors) ==== + declare module "ext" { + ~~~~~ +!!! error TS2664: Invalid module name in augmentation, module 'ext' cannot be found. + } + export {}; + +==== /src/app.ts (0 errors) ==== + import "A" \ No newline at end of file diff --git a/tests/baselines/reference/moduleAugmentationInDependency2.js b/tests/baselines/reference/moduleAugmentationInDependency2.js new file mode 100644 index 00000000000..381f1e72d8f --- /dev/null +++ b/tests/baselines/reference/moduleAugmentationInDependency2.js @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/moduleAugmentationInDependency2.ts] //// + +//// [index.ts] +declare module "ext" { +} +export {}; + +//// [app.ts] +import "A" + +//// [index.js] +"use strict"; +//// [app.js] +"use strict"; +require("A"); diff --git a/tests/baselines/reference/privacyGloImportParseErrors.errors.txt b/tests/baselines/reference/privacyGloImportParseErrors.errors.txt index 05bb3559f1a..6f6c2e5f865 100644 --- a/tests/baselines/reference/privacyGloImportParseErrors.errors.txt +++ b/tests/baselines/reference/privacyGloImportParseErrors.errors.txt @@ -14,12 +14,11 @@ tests/cases/compiler/privacyGloImportParseErrors.ts(125,45): error TS1147: Impor tests/cases/compiler/privacyGloImportParseErrors.ts(133,9): error TS1038: A 'declare' modifier cannot be used in an already ambient context. tests/cases/compiler/privacyGloImportParseErrors.ts(133,24): error TS2435: Ambient modules cannot be nested in other modules or namespaces. tests/cases/compiler/privacyGloImportParseErrors.ts(138,16): error TS2435: Ambient modules cannot be nested in other modules or namespaces. -tests/cases/compiler/privacyGloImportParseErrors.ts(141,12): error TS2664: Invalid module name in augmentation, module 'abc3' cannot be found. tests/cases/compiler/privacyGloImportParseErrors.ts(146,25): error TS1147: Import declarations in a namespace cannot reference a module. tests/cases/compiler/privacyGloImportParseErrors.ts(149,29): error TS1147: Import declarations in a namespace cannot reference a module. -==== tests/cases/compiler/privacyGloImportParseErrors.ts (19 errors) ==== +==== tests/cases/compiler/privacyGloImportParseErrors.ts (18 errors) ==== module m1 { export module m1_M1_public { export class c1 { @@ -193,8 +192,6 @@ tests/cases/compiler/privacyGloImportParseErrors.ts(149,29): error TS1147: Impor } } module "abc3" { - ~~~~~~ -!!! error TS2664: Invalid module name in augmentation, module 'abc3' cannot be found. } } diff --git a/tests/cases/compiler/moduleAugmentationInDependency.ts b/tests/cases/compiler/moduleAugmentationInDependency.ts new file mode 100644 index 00000000000..23d10edbd74 --- /dev/null +++ b/tests/cases/compiler/moduleAugmentationInDependency.ts @@ -0,0 +1,7 @@ +// @filename: /node_modules/A/index.d.ts +declare module "ext" { +} +export {}; + +// @filename: /src/app.ts +import "A" \ No newline at end of file diff --git a/tests/cases/compiler/moduleAugmentationInDependency2.ts b/tests/cases/compiler/moduleAugmentationInDependency2.ts new file mode 100644 index 00000000000..189e020fd2e --- /dev/null +++ b/tests/cases/compiler/moduleAugmentationInDependency2.ts @@ -0,0 +1,7 @@ +// @filename: /node_modules/A/index.ts +declare module "ext" { +} +export {}; + +// @filename: /src/app.ts +import "A" \ No newline at end of file From 6f24144f05484f143f614437d98b0f760804958c Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 19 Apr 2016 16:02:29 -0700 Subject: [PATCH 088/110] Do not transform the emit of function with rest parameter unless declared in AST Fixes #7749 --- src/compiler/checker.ts | 2 +- src/compiler/emitter.ts | 4 +-- src/compiler/utilities.ts | 27 ++++++++++--------- ...jsFileCompilationRestParamJsDocFunction.js | 6 +---- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9d101aab909..566d19ae05b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13811,7 +13811,7 @@ namespace ts { function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact - if (!hasRestParameter(node) || isInAmbientContext(node) || nodeIsMissing((node).body)) { + if (!hasDeclaredRestParameter(node) || isInAmbientContext(node) || nodeIsMissing((node).body)) { return; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 396f178cab2..c4e3c8668fd 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4487,7 +4487,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge } function emitRestParameter(node: FunctionLikeDeclaration) { - if (languageVersion < ScriptTarget.ES6 && hasRestParameter(node)) { + if (languageVersion < ScriptTarget.ES6 && hasDeclaredRestParameter(node)) { const restIndex = node.parameters.length - 1; const restParam = node.parameters[restIndex]; @@ -4644,7 +4644,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge if (node) { const parameters = node.parameters; const skipCount = node.parameters.length && (node.parameters[0].name).text === "this" ? 1 : 0; - const omitCount = languageVersion < ScriptTarget.ES6 && hasRestParameter(node) ? 1 : 0; + const omitCount = languageVersion < ScriptTarget.ES6 && hasDeclaredRestParameter(node) ? 1 : 0; emitList(parameters, skipCount, parameters.length - omitCount - skipCount, /*multiLine*/ false, /*trailingComma*/ false); } write(")"); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e9f63918bbd..b97ad70a74a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1377,23 +1377,26 @@ namespace ts { return isRestParameter(lastOrUndefined(s.parameters)); } - export function isRestParameter(node: ParameterDeclaration) { - if (node) { - if (node.flags & NodeFlags.JavaScriptFile) { - if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType) { - return true; - } + export function hasDeclaredRestParameter(s: SignatureDeclaration): boolean { + return isDeclaredRestParam(lastOrUndefined(s.parameters)); + } - const paramTag = getCorrespondingJSDocParameterTag(node); - if (paramTag && paramTag.typeExpression) { - return paramTag.typeExpression.type.kind === SyntaxKind.JSDocVariadicType; - } + export function isRestParameter(node: ParameterDeclaration) { + if (node && (node.flags & NodeFlags.JavaScriptFile)) { + if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType) { + return true; } - return node.dotDotDotToken !== undefined; + const paramTag = getCorrespondingJSDocParameterTag(node); + if (paramTag && paramTag.typeExpression) { + return paramTag.typeExpression.type.kind === SyntaxKind.JSDocVariadicType; + } } + return isDeclaredRestParam(node); + } - return false; + export function isDeclaredRestParam(node: ParameterDeclaration) { + return node && node.dotDotDotToken !== undefined; } export function isLiteralKind(kind: SyntaxKind): boolean { diff --git a/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js index 9e5c53fbe05..e1675ff7131 100644 --- a/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js +++ b/tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js @@ -36,11 +36,7 @@ define("_apply", ["require", "exports"], function (require, exports) { * @param {...*} args The arguments to invoke `func` with. * @returns {*} Returns the result of `func`. */ - function apply(func, thisArg) { - var args = []; - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } + function apply(func, thisArg, args) { var length = args.length; switch (length) { case 0: return func.call(thisArg); From 24f535ed68b2e838abed54095825203a52ec8383 Mon Sep 17 00:00:00 2001 From: Yui Date: Tue, 19 Apr 2016 16:40:07 -0700 Subject: [PATCH 089/110] Fix missing iterator in NodeList (#8199) --- Jakefile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jakefile.js b/Jakefile.js index 1d017d5100f..3e0512de452 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -203,7 +203,7 @@ var librarySourceMap = [ // JavaScript + all host library { target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources), }, - { target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources), }, + { target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts"), }, ].concat(es2015LibrarySourceMap, es2016LibrarySourceMap); var libraryTargets = librarySourceMap.map(function (f) { From b85f34ba59bafa443a8f97b3fee7c202f1c488c4 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 19 Apr 2016 19:30:11 -0700 Subject: [PATCH 090/110] Fix #8162 and #8173: Add root symbols to search in find all referecnes --- src/services/services.ts | 2 +- .../fourslash/referencesForClassMembers.ts | 32 +++++++++++++++++++ ...esForClassMembersExtendingAbstractClass.ts | 32 +++++++++++++++++++ ...cesForClassMembersExtendingGenericClass.ts | 32 +++++++++++++++++++ .../referencesForInheritedProperties6.ts | 6 ++-- .../referencesForInheritedProperties7.ts | 6 ++-- 6 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 tests/cases/fourslash/referencesForClassMembers.ts create mode 100644 tests/cases/fourslash/referencesForClassMembersExtendingAbstractClass.ts create mode 100644 tests/cases/fourslash/referencesForClassMembersExtendingGenericClass.ts diff --git a/src/services/services.ts b/src/services/services.ts index 333baaec637..d26222d636b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6286,7 +6286,7 @@ namespace ts { if (type) { const propertySymbol = typeChecker.getPropertyOfType(type, propertyName); if (propertySymbol) { - result.push(propertySymbol); + result.push(...typeChecker.getRootSymbols(propertySymbol)); } // Visit the typeReference as well to see if it directly or indirectly use that property diff --git a/tests/cases/fourslash/referencesForClassMembers.ts b/tests/cases/fourslash/referencesForClassMembers.ts new file mode 100644 index 00000000000..851c1b39ab0 --- /dev/null +++ b/tests/cases/fourslash/referencesForClassMembers.ts @@ -0,0 +1,32 @@ +/// + +////class Base { +//// /*1*/a: number; +//// /*2*/method(): void { } +////} +////class MyClass extends Base { +//// /*3*/a; +//// /*4*/method() { } +////} +//// +////var c: MyClass; +////c./*5*/a; +////c./*6*/method(); + +goTo.marker("1"); +verify.referencesCountIs(3); + +goTo.marker("2"); +verify.referencesCountIs(3); + +goTo.marker("3"); +verify.referencesCountIs(3); + +goTo.marker("4"); +verify.referencesCountIs(3); + +goTo.marker("5"); +verify.referencesCountIs(3); + +goTo.marker("6"); +verify.referencesCountIs(3); diff --git a/tests/cases/fourslash/referencesForClassMembersExtendingAbstractClass.ts b/tests/cases/fourslash/referencesForClassMembersExtendingAbstractClass.ts new file mode 100644 index 00000000000..fcabff979fb --- /dev/null +++ b/tests/cases/fourslash/referencesForClassMembersExtendingAbstractClass.ts @@ -0,0 +1,32 @@ +/// + +////abstract class Base { +//// abstract /*1*/a: number; +//// abstract /*2*/method(): void; +////} +////class MyClass extends Base { +//// /*3*/a; +//// /*4*/method() { } +////} +//// +////var c: MyClass; +////c./*5*/a; +////c./*6*/method(); + +goTo.marker("1"); +verify.referencesCountIs(3); + +goTo.marker("2"); +verify.referencesCountIs(3); + +goTo.marker("3"); +verify.referencesCountIs(3); + +goTo.marker("4"); +verify.referencesCountIs(3); + +goTo.marker("5"); +verify.referencesCountIs(3); + +goTo.marker("6"); +verify.referencesCountIs(3); diff --git a/tests/cases/fourslash/referencesForClassMembersExtendingGenericClass.ts b/tests/cases/fourslash/referencesForClassMembersExtendingGenericClass.ts new file mode 100644 index 00000000000..f0185fb39aa --- /dev/null +++ b/tests/cases/fourslash/referencesForClassMembersExtendingGenericClass.ts @@ -0,0 +1,32 @@ +/// + +////class Base { +//// /*1*/a: this; +//// /*2*/method(a?:T, b?:U): this { } +////} +////class MyClass extends Base { +//// /*3*/a; +//// /*4*/method() { } +////} +//// +////var c: MyClass; +////c./*5*/a; +////c./*6*/method(); + +goTo.marker("1"); +verify.referencesCountIs(3); + +goTo.marker("2"); +verify.referencesCountIs(3); + +goTo.marker("3"); +verify.referencesCountIs(3); + +goTo.marker("4"); +verify.referencesCountIs(3); + +goTo.marker("5"); +verify.referencesCountIs(3); + +goTo.marker("6"); +verify.referencesCountIs(3); diff --git a/tests/cases/fourslash/referencesForInheritedProperties6.ts b/tests/cases/fourslash/referencesForInheritedProperties6.ts index de6a2f2eba1..ddd52447dc1 100644 --- a/tests/cases/fourslash/referencesForInheritedProperties6.ts +++ b/tests/cases/fourslash/referencesForInheritedProperties6.ts @@ -14,13 +14,13 @@ //// v./*6*/doStuff(); goTo.marker("1"); -verify.referencesCountIs(1); +verify.referencesCountIs(3); goTo.marker("2"); verify.referencesCountIs(3); goTo.marker("3"); -verify.referencesCountIs(2); +verify.referencesCountIs(3); goTo.marker("4"); verify.referencesCountIs(3); @@ -29,4 +29,4 @@ goTo.marker("5"); verify.referencesCountIs(3); goTo.marker("6"); -verify.referencesCountIs(2); \ No newline at end of file +verify.referencesCountIs(3); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForInheritedProperties7.ts b/tests/cases/fourslash/referencesForInheritedProperties7.ts index 000d4922222..5747e99615f 100644 --- a/tests/cases/fourslash/referencesForInheritedProperties7.ts +++ b/tests/cases/fourslash/referencesForInheritedProperties7.ts @@ -18,7 +18,7 @@ //// v./*8*/doStuff(); goTo.marker("1"); -verify.referencesCountIs(1); +verify.referencesCountIs(3); goTo.marker("2"); verify.referencesCountIs(3); @@ -30,7 +30,7 @@ goTo.marker("4"); verify.referencesCountIs(3); goTo.marker("5"); -verify.referencesCountIs(3); +verify.referencesCountIs(4); goTo.marker("6"); verify.referencesCountIs(4); @@ -39,4 +39,4 @@ goTo.marker("7"); verify.referencesCountIs(4); goTo.marker("8"); -verify.referencesCountIs(3); \ No newline at end of file +verify.referencesCountIs(4); \ No newline at end of file From ea96dfd364f78caf397a21416765a2f48ae55434 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Apr 2016 06:59:28 -0700 Subject: [PATCH 091/110] Support comma operator in type guards --- src/compiler/binder.ts | 2 ++ src/compiler/checker.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 6eefd7c6ef9..91f4247a673 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -630,6 +630,8 @@ namespace ts { return false; case SyntaxKind.InstanceOfKeyword: return isNarrowingExpression(expr.left); + case SyntaxKind.CommaToken: + return isNarrowingExpression(expr.right); } return false; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4731046864e..09d70ac3684 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7677,6 +7677,8 @@ namespace ts { break; case SyntaxKind.InstanceOfKeyword: return narrowTypeByInstanceof(type, expr, assumeTrue); + case SyntaxKind.CommaToken: + return narrowType(type, expr.right, assumeTrue); } return type; } From 33e359ff135856b44b26ba23ce9a275e1e6a3b48 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Apr 2016 07:09:43 -0700 Subject: [PATCH 092/110] Adding test --- .../controlFlow/controlFlowCommaOperator.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/cases/conformance/controlFlow/controlFlowCommaOperator.ts diff --git a/tests/cases/conformance/controlFlow/controlFlowCommaOperator.ts b/tests/cases/conformance/controlFlow/controlFlowCommaOperator.ts new file mode 100644 index 00000000000..d6d49e48f34 --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowCommaOperator.ts @@ -0,0 +1,22 @@ +function f(x: string | number | boolean) { + let y: string | number | boolean = false; + let z: string | number | boolean = false; + if (y = "", typeof x === "string") { + x; // string + y; // string + z; // boolean + } + else if (z = 1, typeof x === "number") { + x; // number + y; // string + z; // number + } + else { + x; // boolean + y; // string + z; // number + } + x; // string | number | boolean + y; // string + z; // number | boolean +} From bab8ef4b10046e7ef2f1d7ed6ebf22b6b07f7d14 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Apr 2016 07:09:53 -0700 Subject: [PATCH 093/110] Accepting new baselines --- .../reference/controlFlowCommaOperator.js | 48 +++++++++++++ .../controlFlowCommaOperator.symbols | 57 +++++++++++++++ .../reference/controlFlowCommaOperator.types | 71 +++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 tests/baselines/reference/controlFlowCommaOperator.js create mode 100644 tests/baselines/reference/controlFlowCommaOperator.symbols create mode 100644 tests/baselines/reference/controlFlowCommaOperator.types diff --git a/tests/baselines/reference/controlFlowCommaOperator.js b/tests/baselines/reference/controlFlowCommaOperator.js new file mode 100644 index 00000000000..55dcc77e075 --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaOperator.js @@ -0,0 +1,48 @@ +//// [controlFlowCommaOperator.ts] +function f(x: string | number | boolean) { + let y: string | number | boolean = false; + let z: string | number | boolean = false; + if (y = "", typeof x === "string") { + x; // string + y; // string + z; // boolean + } + else if (z = 1, typeof x === "number") { + x; // number + y; // string + z; // number + } + else { + x; // boolean + y; // string + z; // number + } + x; // string | number | boolean + y; // string + z; // number | boolean +} + + +//// [controlFlowCommaOperator.js] +function f(x) { + var y = false; + var z = false; + if (y = "", typeof x === "string") { + x; // string + y; // string + z; // boolean + } + else if (z = 1, typeof x === "number") { + x; // number + y; // string + z; // number + } + else { + x; // boolean + y; // string + z; // number + } + x; // string | number | boolean + y; // string + z; // number | boolean +} diff --git a/tests/baselines/reference/controlFlowCommaOperator.symbols b/tests/baselines/reference/controlFlowCommaOperator.symbols new file mode 100644 index 00000000000..f1550b79a68 --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaOperator.symbols @@ -0,0 +1,57 @@ +=== tests/cases/conformance/controlFlow/controlFlowCommaOperator.ts === +function f(x: string | number | boolean) { +>f : Symbol(f, Decl(controlFlowCommaOperator.ts, 0, 0)) +>x : Symbol(x, Decl(controlFlowCommaOperator.ts, 0, 11)) + + let y: string | number | boolean = false; +>y : Symbol(y, Decl(controlFlowCommaOperator.ts, 1, 7)) + + let z: string | number | boolean = false; +>z : Symbol(z, Decl(controlFlowCommaOperator.ts, 2, 7)) + + if (y = "", typeof x === "string") { +>y : Symbol(y, Decl(controlFlowCommaOperator.ts, 1, 7)) +>x : Symbol(x, Decl(controlFlowCommaOperator.ts, 0, 11)) + + x; // string +>x : Symbol(x, Decl(controlFlowCommaOperator.ts, 0, 11)) + + y; // string +>y : Symbol(y, Decl(controlFlowCommaOperator.ts, 1, 7)) + + z; // boolean +>z : Symbol(z, Decl(controlFlowCommaOperator.ts, 2, 7)) + } + else if (z = 1, typeof x === "number") { +>z : Symbol(z, Decl(controlFlowCommaOperator.ts, 2, 7)) +>x : Symbol(x, Decl(controlFlowCommaOperator.ts, 0, 11)) + + x; // number +>x : Symbol(x, Decl(controlFlowCommaOperator.ts, 0, 11)) + + y; // string +>y : Symbol(y, Decl(controlFlowCommaOperator.ts, 1, 7)) + + z; // number +>z : Symbol(z, Decl(controlFlowCommaOperator.ts, 2, 7)) + } + else { + x; // boolean +>x : Symbol(x, Decl(controlFlowCommaOperator.ts, 0, 11)) + + y; // string +>y : Symbol(y, Decl(controlFlowCommaOperator.ts, 1, 7)) + + z; // number +>z : Symbol(z, Decl(controlFlowCommaOperator.ts, 2, 7)) + } + x; // string | number | boolean +>x : Symbol(x, Decl(controlFlowCommaOperator.ts, 0, 11)) + + y; // string +>y : Symbol(y, Decl(controlFlowCommaOperator.ts, 1, 7)) + + z; // number | boolean +>z : Symbol(z, Decl(controlFlowCommaOperator.ts, 2, 7)) +} + diff --git a/tests/baselines/reference/controlFlowCommaOperator.types b/tests/baselines/reference/controlFlowCommaOperator.types new file mode 100644 index 00000000000..53014ceafa7 --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaOperator.types @@ -0,0 +1,71 @@ +=== tests/cases/conformance/controlFlow/controlFlowCommaOperator.ts === +function f(x: string | number | boolean) { +>f : (x: string | number | boolean) => void +>x : string | number | boolean + + let y: string | number | boolean = false; +>y : string | number | boolean +>false : boolean + + let z: string | number | boolean = false; +>z : string | number | boolean +>false : boolean + + if (y = "", typeof x === "string") { +>y = "", typeof x === "string" : boolean +>y = "" : string +>y : string | number | boolean +>"" : string +>typeof x === "string" : boolean +>typeof x : string +>x : string | number | boolean +>"string" : string + + x; // string +>x : string + + y; // string +>y : string + + z; // boolean +>z : boolean + } + else if (z = 1, typeof x === "number") { +>z = 1, typeof x === "number" : boolean +>z = 1 : number +>z : string | number | boolean +>1 : number +>typeof x === "number" : boolean +>typeof x : string +>x : number | boolean +>"number" : string + + x; // number +>x : number + + y; // string +>y : string + + z; // number +>z : number + } + else { + x; // boolean +>x : boolean + + y; // string +>y : string + + z; // number +>z : number + } + x; // string | number | boolean +>x : string | number | boolean + + y; // string +>y : string + + z; // number | boolean +>z : boolean | number +} + From e9a7d3d98c9e657b2b159555ded3665fd750ba9b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Apr 2016 09:15:57 -0700 Subject: [PATCH 094/110] Removing unused logic --- src/compiler/checker.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 09d70ac3684..aa0f9fe2af8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -119,7 +119,6 @@ namespace ts { const nullType = createIntrinsicType(TypeFlags.Null | nullableWideningFlags, "null"); const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined"); const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); - const resolvingFlowType = createIntrinsicType(TypeFlags.Void, "__resolving__"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const emptyUnionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); @@ -7603,11 +7602,7 @@ namespace ts { } function getTypeAtFlowCondition(flow: FlowCondition) { - const type = getTypeAtFlowNode(flow.antecedent); - if (type === resolvingFlowType) { - return type; - } - return narrowType(type, (flow).expression, (flow).assumeTrue); + return narrowType(getTypeAtFlowNode(flow.antecedent), flow.expression, flow.assumeTrue); } function getTypeAtFlowNodeCached(flow: FlowNode) { From 1c24c480732cd72d68cb26bec1cab650beff5214 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 20 Apr 2016 11:32:07 -0700 Subject: [PATCH 095/110] Add emacs temp files to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e1492c2cd73..79fefb71a85 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ tests/cases/perf/* !tests/cases/webharness/compilerToString.js test-args.txt ~*.docx +\#*\# +.\#* tests/baselines/local/* tests/services/baselines/local/* tests/baselines/prototyping/local/* From 350f62ff292a581dc04f2397df4b2238eeb851a9 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Wed, 20 Apr 2016 16:17:29 -0700 Subject: [PATCH 096/110] treat TS only keywords as identifiers in jsdoc comments --- src/compiler/parser.ts | 4 +-- src/compiler/utilities.ts | 29 ++++++++++++++++--- .../server/jsdocParamTagSpecialKeywords.ts | 14 +++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/server/jsdocParamTagSpecialKeywords.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 38a341eaa5a..7ceb09730ff 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6160,7 +6160,7 @@ namespace ts { parseExpected(SyntaxKind.CloseBracketToken); } - else if (token === SyntaxKind.Identifier) { + else if (token === SyntaxKind.Identifier || isTSOnlyKeyword(token)) { name = parseJSDocIdentifier(); } @@ -6259,7 +6259,7 @@ namespace ts { } function parseJSDocIdentifier(): Identifier { - if (token !== SyntaxKind.Identifier) { + if (token !== SyntaxKind.Identifier && !isTSOnlyKeyword(token)) { parseErrorAtCurrentToken(Diagnostics.Identifier_expected); return undefined; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b97ad70a74a..eb5c62844c4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -435,7 +435,7 @@ namespace ts { const { line: startLine } = getLineAndCharacterOfPosition(sourceFile, node.body.pos); const { line: endLine } = getLineAndCharacterOfPosition(sourceFile, node.body.end); if (startLine < endLine) { - // The arrow function spans multiple lines, + // The arrow function spans multiple lines, // make the error span be the first line, inclusive. return createTextSpan(pos, getEndLinePosition(startLine, sourceFile) - pos + 1); } @@ -1301,10 +1301,10 @@ namespace ts { if (node.jsDocComment) { return node.jsDocComment; } - // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. - // /** + // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. + // /** // * @param {number} name - // * @returns {number} + // * @returns {number} // */ // var x = function(name) { return name.length; } if (checkParentVariableStatement) { @@ -1667,6 +1667,27 @@ namespace ts { return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword; } + // Some keywords are TypeScript only, so they should not be parsed as considered as + // keywords in JavaScript + export function isJSKeyword(token: SyntaxKind): boolean { + switch (token) { + case SyntaxKind.TypeKeyword: + case SyntaxKind.AsKeyword: + case SyntaxKind.AnyKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.IsKeyword: + case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.FromKeyword: + return false; + default: + return isKeyword(token); + } + } + + export function isTSOnlyKeyword(token: SyntaxKind): boolean { + return isKeyword(token) && !isJSKeyword(token); + } + export function isTrivia(token: SyntaxKind) { return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken; } diff --git a/tests/cases/fourslash/server/jsdocParamTagSpecialKeywords.ts b/tests/cases/fourslash/server/jsdocParamTagSpecialKeywords.ts new file mode 100644 index 00000000000..be7ca5f0dff --- /dev/null +++ b/tests/cases/fourslash/server/jsdocParamTagSpecialKeywords.ts @@ -0,0 +1,14 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: test.js +//// /** +//// * @param {string} type +//// */ +//// function test(type) { +//// type./**/ +//// } + + +goTo.marker(); +verify.completionListContains("charAt"); \ No newline at end of file From a0101c0787e027725cd3224e71de5177368b556a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 10:48:34 -0700 Subject: [PATCH 097/110] Improve consistency of instanceof and user defined type guards --- src/compiler/checker.ts | 55 ++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa0f9fe2af8..195245648a7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7339,6 +7339,18 @@ namespace ts { return false; } + function typeMaybeSubtypeOf(source: Type, target: Type) { + if (!(source.flags & TypeFlags.Union)) { + return isTypeSubtypeOf(source, target); + } + for (const t of (source).types) { + if (isTypeSubtypeOf(t, target)) { + return true; + } + } + return false; + } + // Remove those constituent types of declaredType to which no constituent type of assignedType is assignable. // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, // we remove type string. @@ -7766,30 +7778,29 @@ namespace ts { return type; } - function getNarrowedType(originalType: Type, narrowedTypeCandidate: Type, assumeTrue: boolean) { - if (!assumeTrue) { - if (originalType.flags & TypeFlags.Union) { - return getUnionType(filter((originalType).types, t => !isTypeSubtypeOf(t, narrowedTypeCandidate))); - } - return originalType; + function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean) { + if (typeMaybeSubtypeOf(type, candidate)) { + // If the current type, or a constituent of the current type, is a subtype of + // the candidate type then the current type contains the most specific information. + // and we simply filter out constituents that aren't applicable. For example, + // if the current type is string | string[] and the candidate type is any[], + // we filter out string. + return type.flags & TypeFlags.Union ? + getUnionType(filter((type).types, t => isTypeSubtypeOf(t, candidate) === assumeTrue)) : + assumeTrue ? type : emptyUnionType; } - - // If the current type is a union type, remove all constituents that aren't assignable to target. If that produces - // 0 candidates, fall back to the assignability check - if (originalType.flags & TypeFlags.Union) { - const assignableConstituents = filter((originalType).types, t => isTypeAssignableTo(t, narrowedTypeCandidate)); - if (assignableConstituents.length) { - return getUnionType(assignableConstituents); - } + if (assumeTrue) { + // In the true branch of the remaining cases, if the candidate type is assignable + // to the current type, then we narrow to the candidate type. Otherwise, we narrow + // to an empty type (because we now know the types are completely unrelated). For + // example, if the current type is Object and the candidate type is string[], we + // narrow to string[]. But if the current type is string and the candidate is + // string[], we narrow to the empty type. + const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type; + return isTypeAssignableTo(candidate, targetType) ? candidate : emptyUnionType; } - - const targetType = originalType.flags & TypeFlags.TypeParameter ? getApparentType(originalType) : originalType; - if (isTypeAssignableTo(narrowedTypeCandidate, targetType)) { - // Narrow to the target type if it's assignable to the current type - return narrowedTypeCandidate; - } - - return originalType; + // In the false branch of the remaining cases we leave the type unchanged. + return type; } function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { From 729dfceb457943363bfa883b91639a673ae7d975 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 10:49:19 -0700 Subject: [PATCH 098/110] Fix incorrect user defined type guard function in compiler --- src/compiler/emitter.ts | 2 +- src/compiler/utilities.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 254b8d7e61b..19c47db2193 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -7084,7 +7084,7 @@ const _super = (function (geti, seti) { hoistedVars = []; } - hoistedVars.push(node.name); + hoistedVars.push((node).name); return; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 60b041d843c..65405db79ae 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1178,7 +1178,7 @@ namespace ts { return ((node).moduleReference).expression; } - export function isInternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration { + export function isInternalModuleImportEqualsDeclaration(node: Node): boolean { return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference; } From 3045cf5fa2a2ea7657b2030e3acebcc69c3779d0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 10:49:39 -0700 Subject: [PATCH 099/110] Add regression test --- .../controlFlowBinaryOrExpression.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts b/tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts index 75b24622e00..9dab32e0cb8 100644 --- a/tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts +++ b/tests/cases/conformance/controlFlow/controlFlowBinaryOrExpression.ts @@ -7,3 +7,29 @@ x; // string | number x = ""; cond || (x = 0); x; // string | number + +export interface NodeList { + length: number; +} + +export interface HTMLCollection { + length: number; +} + +declare function isNodeList(sourceObj: any): sourceObj is NodeList; +declare function isHTMLCollection(sourceObj: any): sourceObj is HTMLCollection; + +type EventTargetLike = {a: string} | HTMLCollection | NodeList; + +var sourceObj: EventTargetLike = undefined; +if (isNodeList(sourceObj)) { + sourceObj.length; +} + +if (isHTMLCollection(sourceObj)) { + sourceObj.length; +} + +if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) { + sourceObj.length; +} From 06928b669e69495333ef51ed3e02332898cdd1b7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 10:50:08 -0700 Subject: [PATCH 100/110] Accepting new baselines --- .../controlFlowBinaryOrExpression.js | 37 +++++++++ .../controlFlowBinaryOrExpression.symbols | 69 +++++++++++++++++ .../controlFlowBinaryOrExpression.types | 75 +++++++++++++++++++ .../reference/instanceOfAssignability.types | 4 +- .../stringLiteralTypesAsTags01.types | 8 +- .../stringLiteralTypesAsTags02.types | 8 +- .../stringLiteralTypesAsTags03.types | 8 +- .../typeGuardsWithInstanceOf.errors.txt | 14 ++++ .../typeGuardsWithInstanceOf.symbols | 26 ------- .../reference/typeGuardsWithInstanceOf.types | 31 -------- 10 files changed, 209 insertions(+), 71 deletions(-) create mode 100644 tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt delete mode 100644 tests/baselines/reference/typeGuardsWithInstanceOf.symbols delete mode 100644 tests/baselines/reference/typeGuardsWithInstanceOf.types diff --git a/tests/baselines/reference/controlFlowBinaryOrExpression.js b/tests/baselines/reference/controlFlowBinaryOrExpression.js index 350e383a1f8..fb48c5a23e0 100644 --- a/tests/baselines/reference/controlFlowBinaryOrExpression.js +++ b/tests/baselines/reference/controlFlowBinaryOrExpression.js @@ -8,9 +8,36 @@ x; // string | number x = ""; cond || (x = 0); x; // string | number + +export interface NodeList { + length: number; +} + +export interface HTMLCollection { + length: number; +} + +declare function isNodeList(sourceObj: any): sourceObj is NodeList; +declare function isHTMLCollection(sourceObj: any): sourceObj is HTMLCollection; + +type EventTargetLike = {a: string} | HTMLCollection | NodeList; + +var sourceObj: EventTargetLike = undefined; +if (isNodeList(sourceObj)) { + sourceObj.length; +} + +if (isHTMLCollection(sourceObj)) { + sourceObj.length; +} + +if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) { + sourceObj.length; +} //// [controlFlowBinaryOrExpression.js] +"use strict"; var x; var cond; (x = "") || (x = 0); @@ -18,3 +45,13 @@ x; // string | number x = ""; cond || (x = 0); x; // string | number +var sourceObj = undefined; +if (isNodeList(sourceObj)) { + sourceObj.length; +} +if (isHTMLCollection(sourceObj)) { + sourceObj.length; +} +if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) { + sourceObj.length; +} diff --git a/tests/baselines/reference/controlFlowBinaryOrExpression.symbols b/tests/baselines/reference/controlFlowBinaryOrExpression.symbols index 286612ef4df..e47bdb19d34 100644 --- a/tests/baselines/reference/controlFlowBinaryOrExpression.symbols +++ b/tests/baselines/reference/controlFlowBinaryOrExpression.symbols @@ -22,3 +22,72 @@ cond || (x = 0); x; // string | number >x : Symbol(x, Decl(controlFlowBinaryOrExpression.ts, 0, 3)) +export interface NodeList { +>NodeList : Symbol(NodeList, Decl(controlFlowBinaryOrExpression.ts, 8, 2)) + + length: number; +>length : Symbol(NodeList.length, Decl(controlFlowBinaryOrExpression.ts, 10, 27)) +} + +export interface HTMLCollection { +>HTMLCollection : Symbol(HTMLCollection, Decl(controlFlowBinaryOrExpression.ts, 12, 1)) + + length: number; +>length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33)) +} + +declare function isNodeList(sourceObj: any): sourceObj is NodeList; +>isNodeList : Symbol(isNodeList, Decl(controlFlowBinaryOrExpression.ts, 16, 1)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 18, 28)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 18, 28)) +>NodeList : Symbol(NodeList, Decl(controlFlowBinaryOrExpression.ts, 8, 2)) + +declare function isHTMLCollection(sourceObj: any): sourceObj is HTMLCollection; +>isHTMLCollection : Symbol(isHTMLCollection, Decl(controlFlowBinaryOrExpression.ts, 18, 67)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 19, 34)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 19, 34)) +>HTMLCollection : Symbol(HTMLCollection, Decl(controlFlowBinaryOrExpression.ts, 12, 1)) + +type EventTargetLike = {a: string} | HTMLCollection | NodeList; +>EventTargetLike : Symbol(EventTargetLike, Decl(controlFlowBinaryOrExpression.ts, 19, 79)) +>a : Symbol(a, Decl(controlFlowBinaryOrExpression.ts, 21, 24)) +>HTMLCollection : Symbol(HTMLCollection, Decl(controlFlowBinaryOrExpression.ts, 12, 1)) +>NodeList : Symbol(NodeList, Decl(controlFlowBinaryOrExpression.ts, 8, 2)) + +var sourceObj: EventTargetLike = undefined; +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) +>EventTargetLike : Symbol(EventTargetLike, Decl(controlFlowBinaryOrExpression.ts, 19, 79)) +>undefined : Symbol(undefined) + +if (isNodeList(sourceObj)) { +>isNodeList : Symbol(isNodeList, Decl(controlFlowBinaryOrExpression.ts, 16, 1)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) + + sourceObj.length; +>sourceObj.length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) +>length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33)) +} + +if (isHTMLCollection(sourceObj)) { +>isHTMLCollection : Symbol(isHTMLCollection, Decl(controlFlowBinaryOrExpression.ts, 18, 67)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) + + sourceObj.length; +>sourceObj.length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) +>length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33)) +} + +if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) { +>isNodeList : Symbol(isNodeList, Decl(controlFlowBinaryOrExpression.ts, 16, 1)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) +>isHTMLCollection : Symbol(isHTMLCollection, Decl(controlFlowBinaryOrExpression.ts, 18, 67)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) + + sourceObj.length; +>sourceObj.length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33)) +>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3)) +>length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33)) +} + diff --git a/tests/baselines/reference/controlFlowBinaryOrExpression.types b/tests/baselines/reference/controlFlowBinaryOrExpression.types index 404e153788a..8c1cd32d8d9 100644 --- a/tests/baselines/reference/controlFlowBinaryOrExpression.types +++ b/tests/baselines/reference/controlFlowBinaryOrExpression.types @@ -35,3 +35,78 @@ cond || (x = 0); x; // string | number >x : string | number +export interface NodeList { +>NodeList : NodeList + + length: number; +>length : number +} + +export interface HTMLCollection { +>HTMLCollection : HTMLCollection + + length: number; +>length : number +} + +declare function isNodeList(sourceObj: any): sourceObj is NodeList; +>isNodeList : (sourceObj: any) => sourceObj is NodeList +>sourceObj : any +>sourceObj : any +>NodeList : NodeList + +declare function isHTMLCollection(sourceObj: any): sourceObj is HTMLCollection; +>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection +>sourceObj : any +>sourceObj : any +>HTMLCollection : HTMLCollection + +type EventTargetLike = {a: string} | HTMLCollection | NodeList; +>EventTargetLike : { a: string; } | HTMLCollection | NodeList +>a : string +>HTMLCollection : HTMLCollection +>NodeList : NodeList + +var sourceObj: EventTargetLike = undefined; +>sourceObj : { a: string; } | HTMLCollection | NodeList +>EventTargetLike : { a: string; } | HTMLCollection | NodeList +>undefined : any +>undefined : undefined + +if (isNodeList(sourceObj)) { +>isNodeList(sourceObj) : boolean +>isNodeList : (sourceObj: any) => sourceObj is NodeList +>sourceObj : { a: string; } | HTMLCollection + + sourceObj.length; +>sourceObj.length : number +>sourceObj : HTMLCollection +>length : number +} + +if (isHTMLCollection(sourceObj)) { +>isHTMLCollection(sourceObj) : boolean +>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection +>sourceObj : HTMLCollection | { a: string; } + + sourceObj.length; +>sourceObj.length : number +>sourceObj : HTMLCollection +>length : number +} + +if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) { +>isNodeList(sourceObj) || isHTMLCollection(sourceObj) : boolean +>isNodeList(sourceObj) : boolean +>isNodeList : (sourceObj: any) => sourceObj is NodeList +>sourceObj : HTMLCollection | { a: string; } +>isHTMLCollection(sourceObj) : boolean +>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection +>sourceObj : { a: string; } + + sourceObj.length; +>sourceObj.length : number +>sourceObj : HTMLCollection +>length : number +} + diff --git a/tests/baselines/reference/instanceOfAssignability.types b/tests/baselines/reference/instanceOfAssignability.types index 12b2d326062..5fa55aa6d88 100644 --- a/tests/baselines/reference/instanceOfAssignability.types +++ b/tests/baselines/reference/instanceOfAssignability.types @@ -133,8 +133,8 @@ function fn5(x: Derived1) { // 1.5: y: Derived1 // Want: ??? let y = x; ->y : Derived1 ->x : Derived1 +>y : {} +>x : {} } } diff --git a/tests/baselines/reference/stringLiteralTypesAsTags01.types b/tests/baselines/reference/stringLiteralTypesAsTags01.types index a7f403e76ec..30f60a5766f 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags01.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags01.types @@ -99,8 +99,8 @@ if (hasKind(x, "A")) { } else { let b = x; ->b : A ->x : A +>b : {} +>x : {} } if (!hasKind(x, "B")) { @@ -116,6 +116,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : A ->x : A +>d : {} +>x : {} } diff --git a/tests/baselines/reference/stringLiteralTypesAsTags02.types b/tests/baselines/reference/stringLiteralTypesAsTags02.types index edad220b086..58a22097864 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags02.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags02.types @@ -93,8 +93,8 @@ if (hasKind(x, "A")) { } else { let b = x; ->b : A ->x : A +>b : {} +>x : {} } if (!hasKind(x, "B")) { @@ -110,6 +110,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : A ->x : A +>d : {} +>x : {} } diff --git a/tests/baselines/reference/stringLiteralTypesAsTags03.types b/tests/baselines/reference/stringLiteralTypesAsTags03.types index 25816659388..a7cef3ec203 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags03.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags03.types @@ -96,8 +96,8 @@ if (hasKind(x, "A")) { } else { let b = x; ->b : A ->x : A +>b : {} +>x : {} } if (!hasKind(x, "B")) { @@ -113,6 +113,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : A ->x : A +>d : {} +>x : {} } diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt new file mode 100644 index 00000000000..28cc85695bc --- /dev/null +++ b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt @@ -0,0 +1,14 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(7,20): error TS2339: Property 'global' does not exist on type '{}'. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts (1 errors) ==== + interface I { global: string; } + var result: I; + var result2: I; + + if (!(result instanceof RegExp)) { + result = result2; + } else if (!result.global) { + ~~~~~~ +!!! error TS2339: Property 'global' does not exist on type '{}'. + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.symbols b/tests/baselines/reference/typeGuardsWithInstanceOf.symbols deleted file mode 100644 index cc2695e6aea..00000000000 --- a/tests/baselines/reference/typeGuardsWithInstanceOf.symbols +++ /dev/null @@ -1,26 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts === -interface I { global: string; } ->I : Symbol(I, Decl(typeGuardsWithInstanceOf.ts, 0, 0)) ->global : Symbol(I.global, Decl(typeGuardsWithInstanceOf.ts, 0, 13)) - -var result: I; ->result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3)) ->I : Symbol(I, Decl(typeGuardsWithInstanceOf.ts, 0, 0)) - -var result2: I; ->result2 : Symbol(result2, Decl(typeGuardsWithInstanceOf.ts, 2, 3)) ->I : Symbol(I, Decl(typeGuardsWithInstanceOf.ts, 0, 0)) - -if (!(result instanceof RegExp)) { ->result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3)) ->RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) - - result = result2; ->result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3)) ->result2 : Symbol(result2, Decl(typeGuardsWithInstanceOf.ts, 2, 3)) - -} else if (!result.global) { ->result.global : Symbol(I.global, Decl(typeGuardsWithInstanceOf.ts, 0, 13)) ->result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3)) ->global : Symbol(I.global, Decl(typeGuardsWithInstanceOf.ts, 0, 13)) -} diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.types b/tests/baselines/reference/typeGuardsWithInstanceOf.types deleted file mode 100644 index 0d7b477faed..00000000000 --- a/tests/baselines/reference/typeGuardsWithInstanceOf.types +++ /dev/null @@ -1,31 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts === -interface I { global: string; } ->I : I ->global : string - -var result: I; ->result : I ->I : I - -var result2: I; ->result2 : I ->I : I - -if (!(result instanceof RegExp)) { ->!(result instanceof RegExp) : boolean ->(result instanceof RegExp) : boolean ->result instanceof RegExp : boolean ->result : I ->RegExp : RegExpConstructor - - result = result2; ->result = result2 : I ->result : I ->result2 : I - -} else if (!result.global) { ->!result.global : boolean ->result.global : string ->result : I ->global : string -} From 8a0bc3b992328adc2fd40efb52d7f0d1d81c3604 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 13:02:52 -0700 Subject: [PATCH 101/110] Support assignments in truthiness type guards --- src/compiler/binder.ts | 2 ++ src/compiler/checker.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 91f4247a673..3d6db01580a 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -617,6 +617,8 @@ namespace ts { function isNarrowingBinaryExpression(expr: BinaryExpression) { switch (expr.operatorToken.kind) { + case SyntaxKind.EqualsToken: + return isNarrowableReference(expr.left); case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 195245648a7..a3b3451fe35 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7671,6 +7671,8 @@ namespace ts { function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { switch (expr.operatorToken.kind) { + case SyntaxKind.EqualsToken: + return narrowTypeByTruthiness(type, expr.left, assumeTrue); case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: From d2b89be4bc6788d5d1f9367f1176aaf8f1118daa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 13:03:08 -0700 Subject: [PATCH 102/110] Adding test --- .../reference/controlFlowTruthiness.js | 134 +++++++++++++++ .../reference/controlFlowTruthiness.symbols | 143 ++++++++++++++++ .../reference/controlFlowTruthiness.types | 160 ++++++++++++++++++ .../controlFlow/controlFlowTruthiness.ts | 70 ++++++++ 4 files changed, 507 insertions(+) create mode 100644 tests/baselines/reference/controlFlowTruthiness.js create mode 100644 tests/baselines/reference/controlFlowTruthiness.symbols create mode 100644 tests/baselines/reference/controlFlowTruthiness.types create mode 100644 tests/cases/conformance/controlFlow/controlFlowTruthiness.ts diff --git a/tests/baselines/reference/controlFlowTruthiness.js b/tests/baselines/reference/controlFlowTruthiness.js new file mode 100644 index 00000000000..b595bcbd180 --- /dev/null +++ b/tests/baselines/reference/controlFlowTruthiness.js @@ -0,0 +1,134 @@ +//// [controlFlowTruthiness.ts] + +declare function foo(): string | undefined; + +function f1() { + let x = foo(); + if (x) { + x; // string + } + else { + x; // string | undefined + } +} + +function f2() { + let x: string | undefined; + x = foo(); + if (x) { + x; // string + } + else { + x; // string | undefined + } +} + +function f3() { + let x: string | undefined; + if (x = foo()) { + x; // string + } + else { + x; // string | undefined + } +} + +function f4() { + let x: string | undefined; + if (!(x = foo())) { + x; // string | undefined + } + else { + x; // string + } +} + +function f5() { + let x: string | undefined; + let y: string | undefined; + if (x = y = foo()) { + x; // string + y; // string | undefined + } + else { + x; // string | undefined + y; // string | undefined + } +} + +function f6() { + let x: string | undefined; + let y: string | undefined; + if (x = foo(), y = foo()) { + x; // string | undefined + y; // string + } + else { + x; // string | undefined + y; // string | undefined + } +} + + +//// [controlFlowTruthiness.js] +function f1() { + var x = foo(); + if (x) { + x; // string + } + else { + x; // string | undefined + } +} +function f2() { + var x; + x = foo(); + if (x) { + x; // string + } + else { + x; // string | undefined + } +} +function f3() { + var x; + if (x = foo()) { + x; // string + } + else { + x; // string | undefined + } +} +function f4() { + var x; + if (!(x = foo())) { + x; // string | undefined + } + else { + x; // string + } +} +function f5() { + var x; + var y; + if (x = y = foo()) { + x; // string + y; // string | undefined + } + else { + x; // string | undefined + y; // string | undefined + } +} +function f6() { + var x; + var y; + if (x = foo(), y = foo()) { + x; // string | undefined + y; // string + } + else { + x; // string | undefined + y; // string | undefined + } +} diff --git a/tests/baselines/reference/controlFlowTruthiness.symbols b/tests/baselines/reference/controlFlowTruthiness.symbols new file mode 100644 index 00000000000..37c1fb135f2 --- /dev/null +++ b/tests/baselines/reference/controlFlowTruthiness.symbols @@ -0,0 +1,143 @@ +=== tests/cases/conformance/controlFlow/controlFlowTruthiness.ts === + +declare function foo(): string | undefined; +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) + +function f1() { +>f1 : Symbol(f1, Decl(controlFlowTruthiness.ts, 1, 43)) + + let x = foo(); +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 4, 7)) +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) + + if (x) { +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 4, 7)) + + x; // string +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 4, 7)) + } + else { + x; // string | undefined +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 4, 7)) + } +} + +function f2() { +>f2 : Symbol(f2, Decl(controlFlowTruthiness.ts, 11, 1)) + + let x: string | undefined; +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 14, 7)) + + x = foo(); +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 14, 7)) +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) + + if (x) { +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 14, 7)) + + x; // string +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 14, 7)) + } + else { + x; // string | undefined +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 14, 7)) + } +} + +function f3() { +>f3 : Symbol(f3, Decl(controlFlowTruthiness.ts, 22, 1)) + + let x: string | undefined; +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 25, 7)) + + if (x = foo()) { +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 25, 7)) +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) + + x; // string +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 25, 7)) + } + else { + x; // string | undefined +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 25, 7)) + } +} + +function f4() { +>f4 : Symbol(f4, Decl(controlFlowTruthiness.ts, 32, 1)) + + let x: string | undefined; +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 35, 7)) + + if (!(x = foo())) { +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 35, 7)) +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) + + x; // string | undefined +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 35, 7)) + } + else { + x; // string +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 35, 7)) + } +} + +function f5() { +>f5 : Symbol(f5, Decl(controlFlowTruthiness.ts, 42, 1)) + + let x: string | undefined; +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 45, 7)) + + let y: string | undefined; +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 46, 7)) + + if (x = y = foo()) { +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 45, 7)) +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 46, 7)) +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) + + x; // string +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 45, 7)) + + y; // string | undefined +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 46, 7)) + } + else { + x; // string | undefined +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 45, 7)) + + y; // string | undefined +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 46, 7)) + } +} + +function f6() { +>f6 : Symbol(f6, Decl(controlFlowTruthiness.ts, 55, 1)) + + let x: string | undefined; +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 58, 7)) + + let y: string | undefined; +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 59, 7)) + + if (x = foo(), y = foo()) { +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 58, 7)) +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 59, 7)) +>foo : Symbol(foo, Decl(controlFlowTruthiness.ts, 0, 0)) + + x; // string | undefined +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 58, 7)) + + y; // string +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 59, 7)) + } + else { + x; // string | undefined +>x : Symbol(x, Decl(controlFlowTruthiness.ts, 58, 7)) + + y; // string | undefined +>y : Symbol(y, Decl(controlFlowTruthiness.ts, 59, 7)) + } +} + diff --git a/tests/baselines/reference/controlFlowTruthiness.types b/tests/baselines/reference/controlFlowTruthiness.types new file mode 100644 index 00000000000..2d35856fe83 --- /dev/null +++ b/tests/baselines/reference/controlFlowTruthiness.types @@ -0,0 +1,160 @@ +=== tests/cases/conformance/controlFlow/controlFlowTruthiness.ts === + +declare function foo(): string | undefined; +>foo : () => string | undefined + +function f1() { +>f1 : () => void + + let x = foo(); +>x : string | undefined +>foo() : string | undefined +>foo : () => string | undefined + + if (x) { +>x : string | undefined + + x; // string +>x : string + } + else { + x; // string | undefined +>x : string | undefined + } +} + +function f2() { +>f2 : () => void + + let x: string | undefined; +>x : string | undefined + + x = foo(); +>x = foo() : string | undefined +>x : string | undefined +>foo() : string | undefined +>foo : () => string | undefined + + if (x) { +>x : string | undefined + + x; // string +>x : string + } + else { + x; // string | undefined +>x : string | undefined + } +} + +function f3() { +>f3 : () => void + + let x: string | undefined; +>x : string | undefined + + if (x = foo()) { +>x = foo() : string | undefined +>x : string | undefined +>foo() : string | undefined +>foo : () => string | undefined + + x; // string +>x : string + } + else { + x; // string | undefined +>x : string | undefined + } +} + +function f4() { +>f4 : () => void + + let x: string | undefined; +>x : string | undefined + + if (!(x = foo())) { +>!(x = foo()) : boolean +>(x = foo()) : string | undefined +>x = foo() : string | undefined +>x : string | undefined +>foo() : string | undefined +>foo : () => string | undefined + + x; // string | undefined +>x : string | undefined + } + else { + x; // string +>x : string + } +} + +function f5() { +>f5 : () => void + + let x: string | undefined; +>x : string | undefined + + let y: string | undefined; +>y : string | undefined + + if (x = y = foo()) { +>x = y = foo() : string | undefined +>x : string | undefined +>y = foo() : string | undefined +>y : string | undefined +>foo() : string | undefined +>foo : () => string | undefined + + x; // string +>x : string + + y; // string | undefined +>y : string | undefined + } + else { + x; // string | undefined +>x : string | undefined + + y; // string | undefined +>y : string | undefined + } +} + +function f6() { +>f6 : () => void + + let x: string | undefined; +>x : string | undefined + + let y: string | undefined; +>y : string | undefined + + if (x = foo(), y = foo()) { +>x = foo(), y = foo() : string | undefined +>x = foo() : string | undefined +>x : string | undefined +>foo() : string | undefined +>foo : () => string | undefined +>y = foo() : string | undefined +>y : string | undefined +>foo() : string | undefined +>foo : () => string | undefined + + x; // string | undefined +>x : string | undefined + + y; // string +>y : string + } + else { + x; // string | undefined +>x : string | undefined + + y; // string | undefined +>y : string | undefined + } +} + diff --git a/tests/cases/conformance/controlFlow/controlFlowTruthiness.ts b/tests/cases/conformance/controlFlow/controlFlowTruthiness.ts new file mode 100644 index 00000000000..ba1947da13b --- /dev/null +++ b/tests/cases/conformance/controlFlow/controlFlowTruthiness.ts @@ -0,0 +1,70 @@ +// @strictNullChecks: true + +declare function foo(): string | undefined; + +function f1() { + let x = foo(); + if (x) { + x; // string + } + else { + x; // string | undefined + } +} + +function f2() { + let x: string | undefined; + x = foo(); + if (x) { + x; // string + } + else { + x; // string | undefined + } +} + +function f3() { + let x: string | undefined; + if (x = foo()) { + x; // string + } + else { + x; // string | undefined + } +} + +function f4() { + let x: string | undefined; + if (!(x = foo())) { + x; // string | undefined + } + else { + x; // string + } +} + +function f5() { + let x: string | undefined; + let y: string | undefined; + if (x = y = foo()) { + x; // string + y; // string | undefined + } + else { + x; // string | undefined + y; // string | undefined + } +} + +function f6() { + let x: string | undefined; + let y: string | undefined; + if (x = foo(), y = foo()) { + x; // string | undefined + y; // string + } + else { + x; // string | undefined + y; // string | undefined + } +} From ab4b03983b049adcc2b9cb4cf522b0ebaf8605f6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 13:40:57 -0700 Subject: [PATCH 103/110] Removing unused logic --- src/compiler/checker.ts | 21 +++++---------------- src/compiler/types.ts | 5 ----- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a3b3451fe35..6bffe78bc75 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7197,19 +7197,7 @@ namespace ts { // EXPRESSION TYPE CHECKING - function createTransientIdentifier(symbol: Symbol, location: Node): Identifier { - const result = createNode(SyntaxKind.Identifier); - result.text = symbol.name; - result.resolvedSymbol = symbol; - result.parent = location; - result.id = -1; - return result; - } - function getResolvedSymbol(node: Identifier): Symbol { - if (node.id === -1) { - return (node).resolvedSymbol; - } const links = getNodeLinks(node); if (!links.resolvedSymbol) { links.resolvedSymbol = !nodeIsMissing(node) && resolveName(node, node.text, SymbolFlags.Value | SymbolFlags.ExportValue, Diagnostics.Cannot_find_name_0, node) || unknownSymbol; @@ -7867,7 +7855,7 @@ namespace ts { } // If location is an identifier or property access that references the given // symbol, use the location as the reference with respect to which we narrow. - if (isExpression(location)) { + if (isExpression(location) && !isAssignmentTarget(location)) { checkExpression(location); if (getNodeLinks(location).resolvedSymbol === symbol) { return getNarrowedTypeOfReference(type, location); @@ -7876,9 +7864,10 @@ namespace ts { } // The location isn't a reference to the given symbol, meaning we're being asked // a hypothetical question of what type the symbol would have if there was a reference - // to it at the given location. To answer that question we manufacture a transient - // identifier at the location and narrow with respect to that identifier. - return getNarrowedTypeOfReference(type, createTransientIdentifier(symbol, location)); + // to it at the given location. Since we have no control flow information for the + // hypotherical reference (control flow information is created and attached by the + // binder), we simply return the declared type of the symbol. + return type; } function skipParenthesizedNodes(expression: Expression): Expression { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b5e33d5d361..0a4de847c00 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -479,11 +479,6 @@ namespace ts { originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later } - // Transient identifier node (marked by id === -1) - export interface TransientIdentifier extends Identifier { - resolvedSymbol: Symbol; - } - // @kind(SyntaxKind.QualifiedName) export interface QualifiedName extends Node { // Must have same layout as PropertyAccess From 46f4bd4215412bb9f01e3baf09d960e2ed9c6f6a Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 21 Apr 2016 13:38:47 -0700 Subject: [PATCH 104/110] Allow keywords in jsdoc comments parsing --- src/compiler/parser.ts | 24 ++++++++++++++---------- src/compiler/utilities.ts | 21 --------------------- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7ceb09730ff..c6dd6a769eb 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -886,7 +886,7 @@ namespace ts { /** Invokes the provided callback then unconditionally restores the parser to the state it * was in immediately prior to invoking the callback. The result of invoking the callback - * is returned from this function. + * is returned from this function. */ function lookAhead(callback: () => T): T { return speculationHelper(callback, /*isLookAhead*/ true); @@ -4988,7 +4988,7 @@ namespace ts { if (token === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { // We need to ensure that any subsequent modifiers appear on the same line - // so that when 'const' is a standalone declaration, we don't issue an error. + // so that when 'const' is a standalone declaration, we don't issue an error. if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { break; } @@ -5251,7 +5251,7 @@ namespace ts { node.decorators = decorators; setModifiers(node, modifiers); if (token === SyntaxKind.GlobalKeyword) { - // parse 'global' as name of global scope augmentation + // parse 'global' as name of global scope augmentation node.name = parseIdentifier(); node.flags |= NodeFlags.GlobalAugmentation; } @@ -6087,7 +6087,7 @@ namespace ts { atToken.end = scanner.getTextPos(); nextJSDocToken(); - const tagName = parseJSDocIdentifier(); + const tagName = parseJSDocIdentifierName(); if (!tagName) { return; } @@ -6150,7 +6150,7 @@ namespace ts { let isBracketed: boolean; // Looking for something like '[foo]' or 'foo' if (parseOptionalToken(SyntaxKind.OpenBracketToken)) { - name = parseJSDocIdentifier(); + name = parseJSDocIdentifierName(); isBracketed = true; // May have an optional default, e.g. '[foo = 42]' @@ -6160,8 +6160,8 @@ namespace ts { parseExpected(SyntaxKind.CloseBracketToken); } - else if (token === SyntaxKind.Identifier || isTSOnlyKeyword(token)) { - name = parseJSDocIdentifier(); + else if (tokenIsIdentifierOrKeyword(token)) { + name = parseJSDocIdentifierName(); } if (!name) { @@ -6225,7 +6225,7 @@ namespace ts { typeParameters.pos = scanner.getStartPos(); while (true) { - const name = parseJSDocIdentifier(); + const name = parseJSDocIdentifierName(); if (!name) { parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); return undefined; @@ -6258,8 +6258,12 @@ namespace ts { return token = scanner.scanJSDocToken(); } - function parseJSDocIdentifier(): Identifier { - if (token !== SyntaxKind.Identifier && !isTSOnlyKeyword(token)) { + function parseJSDocIdentifierName(): Identifier { + return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token)); + } + + function createJSDocIdentifier(isIdentifier: boolean): Identifier { + if (!isIdentifier) { parseErrorAtCurrentToken(Diagnostics.Identifier_expected); return undefined; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index eb5c62844c4..db906c57067 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1667,27 +1667,6 @@ namespace ts { return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword; } - // Some keywords are TypeScript only, so they should not be parsed as considered as - // keywords in JavaScript - export function isJSKeyword(token: SyntaxKind): boolean { - switch (token) { - case SyntaxKind.TypeKeyword: - case SyntaxKind.AsKeyword: - case SyntaxKind.AnyKeyword: - case SyntaxKind.DeclareKeyword: - case SyntaxKind.IsKeyword: - case SyntaxKind.ReadonlyKeyword: - case SyntaxKind.FromKeyword: - return false; - default: - return isKeyword(token); - } - } - - export function isTSOnlyKeyword(token: SyntaxKind): boolean { - return isKeyword(token) && !isJSKeyword(token); - } - export function isTrivia(token: SyntaxKind) { return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken; } From 1401e504ac92c80d07265d40ae9e58d4a862274a Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 21 Apr 2016 15:14:58 -0700 Subject: [PATCH 105/110] Provide server response when reload is done --- src/server/session.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/session.ts b/src/server/session.ts index 6fe8ed7b075..2adceee71ae 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1033,7 +1033,7 @@ namespace ts.server { [CommandNames.Reload]: (request: protocol.Request) => { const reloadArgs = request.arguments; this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq); - return {responseRequired: false}; + return {response: { reloadFinished: true }, responseRequired: true}; }, [CommandNames.Saveto]: (request: protocol.Request) => { const savetoArgs = request.arguments; From e12b2a7d276b82ab803e0c1d0e06a687bf557fb7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 16:06:05 -0700 Subject: [PATCH 106/110] Correct issue with exported variables in code flow analysis --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6bffe78bc75..ce17db0bd9a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7576,7 +7576,7 @@ namespace ts { // only need to evaluate the assigned type if the declared type is a union type. if ((node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) && reference.kind === SyntaxKind.Identifier && - getResolvedSymbol(reference) === getSymbolOfNode(node)) { + getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(reference)) === getSymbolOfNode(node)) { return declaredType.flags & TypeFlags.Union ? getAssignmentReducedType(declaredType, getInitialType(node)) : declaredType; @@ -7857,7 +7857,7 @@ namespace ts { // symbol, use the location as the reference with respect to which we narrow. if (isExpression(location) && !isAssignmentTarget(location)) { checkExpression(location); - if (getNodeLinks(location).resolvedSymbol === symbol) { + if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) { return getNarrowedTypeOfReference(type, location); } } @@ -9745,7 +9745,7 @@ namespace ts { } const propType = getTypeOfSymbol(prop); - return node.kind === SyntaxKind.PropertyAccessExpression && prop.flags & SymbolFlags.Property && !isAssignmentTarget(node) ? + return node.kind === SyntaxKind.PropertyAccessExpression && prop.flags & (SymbolFlags.Variable | SymbolFlags.Property) && !isAssignmentTarget(node) ? getNarrowedTypeOfReference(propType, node) : propType; } From 4fb31acf2f52b37a5f3145f52ea4c4495e6f4b26 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 Apr 2016 16:06:21 -0700 Subject: [PATCH 107/110] Update fourslash test --- .../fourslash/quickInfoOnNarrowedTypeInModule.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/cases/fourslash/quickInfoOnNarrowedTypeInModule.ts b/tests/cases/fourslash/quickInfoOnNarrowedTypeInModule.ts index b2826d01650..1f95de35403 100644 --- a/tests/cases/fourslash/quickInfoOnNarrowedTypeInModule.ts +++ b/tests/cases/fourslash/quickInfoOnNarrowedTypeInModule.ts @@ -38,7 +38,19 @@ goTo.marker('3'); verify.quickInfoIs('var nonExportedStrOrNum: string'); verify.completionListContains("nonExportedStrOrNum", "var nonExportedStrOrNum: string"); -['4', '5', '6', '7', '8', '9'].forEach((marker, index, arr) => { +goTo.marker('4'); +verify.quickInfoIs('var m.exportedStrOrNum: string | number'); +verify.completionListContains("exportedStrOrNum", "var m.exportedStrOrNum: string | number"); + +goTo.marker('5'); +verify.quickInfoIs('var m.exportedStrOrNum: number'); +verify.completionListContains("exportedStrOrNum", "var m.exportedStrOrNum: number"); + +goTo.marker('6'); +verify.quickInfoIs('var m.exportedStrOrNum: string'); +verify.completionListContains("exportedStrOrNum", "var m.exportedStrOrNum: string"); + +['7', '8', '9'].forEach((marker, index, arr) => { goTo.marker(marker); verify.quickInfoIs('var m.exportedStrOrNum: string | number'); verify.completionListContains("exportedStrOrNum", "var m.exportedStrOrNum: string | number"); From f06d3f698193821951717e5d5d92057f1b35fd70 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 22 Apr 2016 06:52:14 -0700 Subject: [PATCH 108/110] Only narrow to {} in getNarrowedType when types are completely unrelated --- src/compiler/checker.ts | 48 +++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ce17db0bd9a..583f6c82b32 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7327,18 +7327,6 @@ namespace ts { return false; } - function typeMaybeSubtypeOf(source: Type, target: Type) { - if (!(source.flags & TypeFlags.Union)) { - return isTypeSubtypeOf(source, target); - } - for (const t of (source).types) { - if (isTypeSubtypeOf(t, target)) { - return true; - } - } - return false; - } - // Remove those constituent types of declaredType to which no constituent type of assignedType is assignable. // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, // we remove type string. @@ -7769,28 +7757,26 @@ namespace ts { } function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean) { - if (typeMaybeSubtypeOf(type, candidate)) { - // If the current type, or a constituent of the current type, is a subtype of - // the candidate type then the current type contains the most specific information. - // and we simply filter out constituents that aren't applicable. For example, - // if the current type is string | string[] and the candidate type is any[], - // we filter out string. + if (!assumeTrue) { return type.flags & TypeFlags.Union ? - getUnionType(filter((type).types, t => isTypeSubtypeOf(t, candidate) === assumeTrue)) : - assumeTrue ? type : emptyUnionType; + getUnionType(filter((type).types, t => !isTypeSubtypeOf(t, candidate))) : + type; } - if (assumeTrue) { - // In the true branch of the remaining cases, if the candidate type is assignable - // to the current type, then we narrow to the candidate type. Otherwise, we narrow - // to an empty type (because we now know the types are completely unrelated). For - // example, if the current type is Object and the candidate type is string[], we - // narrow to string[]. But if the current type is string and the candidate is - // string[], we narrow to the empty type. - const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type; - return isTypeAssignableTo(candidate, targetType) ? candidate : emptyUnionType; + // If the current type is a union type, remove all constituents that aren't assignable to + // the candidate type. If one or more constituents remain, return a union of those. + if (type.flags & TypeFlags.Union) { + const assignableConstituents = filter((type).types, t => isTypeAssignableTo(t, candidate)); + if (assignableConstituents.length) { + return getUnionType(assignableConstituents); + } } - // In the false branch of the remaining cases we leave the type unchanged. - return type; + // If the candidate type is assignable to the target type, narrow to the candidate type. + // Otherwise, if the current type is assignable to the candidate, keep the current type. + // Otherwise, the types are completely unrelated, so narrow to the empty type. + const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type; + return isTypeAssignableTo(candidate, targetType) ? candidate : + isTypeAssignableTo(type, candidate) ? type : + emptyUnionType; } function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { From 42e3fc4303f3a74a23e43fb12c0e94cbe37cc8dc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 22 Apr 2016 06:53:01 -0700 Subject: [PATCH 109/110] Revert previous change --- src/compiler/emitter.ts | 2 +- src/compiler/utilities.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 19c47db2193..254b8d7e61b 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -7084,7 +7084,7 @@ const _super = (function (geti, seti) { hoistedVars = []; } - hoistedVars.push((node).name); + hoistedVars.push(node.name); return; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 65405db79ae..60b041d843c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1178,7 +1178,7 @@ namespace ts { return ((node).moduleReference).expression; } - export function isInternalModuleImportEqualsDeclaration(node: Node): boolean { + export function isInternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration { return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference; } From 0dee5addf3b129d9241e7dd57e895cea8ec7dfac Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 22 Apr 2016 06:53:28 -0700 Subject: [PATCH 110/110] Accepting new baselines --- tests/baselines/reference/stringLiteralTypesAsTags01.types | 4 ++-- tests/baselines/reference/stringLiteralTypesAsTags02.types | 4 ++-- tests/baselines/reference/stringLiteralTypesAsTags03.types | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/stringLiteralTypesAsTags01.types b/tests/baselines/reference/stringLiteralTypesAsTags01.types index 30f60a5766f..243b55c4419 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags01.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags01.types @@ -99,8 +99,8 @@ if (hasKind(x, "A")) { } else { let b = x; ->b : {} ->x : {} +>b : A +>x : A } if (!hasKind(x, "B")) { diff --git a/tests/baselines/reference/stringLiteralTypesAsTags02.types b/tests/baselines/reference/stringLiteralTypesAsTags02.types index 58a22097864..20834e1dfef 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags02.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags02.types @@ -93,8 +93,8 @@ if (hasKind(x, "A")) { } else { let b = x; ->b : {} ->x : {} +>b : A +>x : A } if (!hasKind(x, "B")) { diff --git a/tests/baselines/reference/stringLiteralTypesAsTags03.types b/tests/baselines/reference/stringLiteralTypesAsTags03.types index a7cef3ec203..78ad260b719 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags03.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags03.types @@ -96,8 +96,8 @@ if (hasKind(x, "A")) { } else { let b = x; ->b : {} ->x : {} +>b : A +>x : A } if (!hasKind(x, "B")) {