Merge branch 'master' into dynamicNames

This commit is contained in:
Ron Buckton 2017-09-22 14:45:22 -07:00
commit e81c83cdc7
13 changed files with 195 additions and 193 deletions

View File

@ -2430,15 +2430,6 @@ namespace ts {
}
};
interface NodeBuilderContext {
enclosingDeclaration: Node | undefined;
flags: NodeBuilderFlags | undefined;
// State
encounteredError: boolean;
symbolStack: Symbol[] | undefined;
}
function createNodeBuilderContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeBuilderContext {
return {
enclosingDeclaration,
@ -3037,30 +3028,6 @@ namespace ts {
}
}
}
function getNameOfSymbol(symbol: Symbol, context: NodeBuilderContext): string {
const declaration = firstOrUndefined(symbol.declarations);
if (declaration) {
const name = getNameOfDeclaration(declaration);
if (name) {
return declarationNameToString(name);
}
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((<VariableDeclaration>declaration.parent).name);
}
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) {
context.encounteredError = true;
}
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return "(Anonymous function)";
}
}
return unescapeLeadingUnderscores(symbol.escapedName);
}
}
function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
@ -3125,7 +3092,16 @@ namespace ts {
return type.flags & TypeFlags.StringLiteral ? '"' + escapeString((<StringLiteralType>type).value) + '"' : "" + (<NumberLiteralType>type).value;
}
function getNameOfSymbol(symbol: Symbol): string {
interface NodeBuilderContext {
enclosingDeclaration: Node | undefined;
flags: NodeBuilderFlags | undefined;
// State
encounteredError: boolean;
symbolStack: Symbol[] | undefined;
}
function getNameOfSymbol(symbol: Symbol, context?: NodeBuilderContext): string {
if (symbol.declarations && symbol.declarations.length) {
const declaration = symbol.declarations[0];
const name = getNameOfDeclaration(declaration);
@ -3135,6 +3111,9 @@ namespace ts {
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((<VariableDeclaration>declaration.parent).name);
}
if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) {
context.encounteredError = true;
}
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
@ -13436,16 +13415,11 @@ namespace ts {
// the type of the property with the numeric name N in T, if one exists. Otherwise, if T has a numeric index signature,
// it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated
// type of T.
function getContextualTypeForElementExpression(node: Expression): Type {
const arrayLiteral = <ArrayLiteralExpression>node.parent;
const type = getApparentTypeOfContextualType(arrayLiteral);
if (type) {
const index = indexOf(arrayLiteral.elements, node);
return getTypeOfPropertyOfContextualType(type, "" + index as __String)
|| getIndexTypeOfContextualType(type, IndexKind.Number)
|| getIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false, /*checkAssignability*/ false);
}
return undefined;
function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined {
return arrayContextualType && (
getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String)
|| getIndexTypeOfContextualType(arrayContextualType, IndexKind.Number)
|| getIteratedTypeOrElementType(arrayContextualType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false, /*checkAssignability*/ false));
}
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
@ -13559,15 +13533,21 @@ namespace ts {
return getContextualTypeForObjectLiteralElement(<ObjectLiteralElementLike>parent);
case SyntaxKind.SpreadAssignment:
return getApparentTypeOfContextualType(parent.parent as ObjectLiteralExpression);
case SyntaxKind.ArrayLiteralExpression:
return getContextualTypeForElementExpression(node);
case SyntaxKind.ArrayLiteralExpression: {
const arrayLiteral = <ArrayLiteralExpression>parent;
const type = getApparentTypeOfContextualType(arrayLiteral);
return getContextualTypeForElementExpression(type, indexOfNode(arrayLiteral.elements, node));
}
case SyntaxKind.ConditionalExpression:
return getContextualTypeForConditionalOperand(node);
case SyntaxKind.TemplateSpan:
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
case SyntaxKind.ParenthesizedExpression:
return getContextualType(<ParenthesizedExpression>parent);
case SyntaxKind.ParenthesizedExpression: {
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
const tag = isInJavaScriptFile(parent) ? getJSDocTypeTag(parent) : undefined;
return tag ? getTypeFromTypeNode(tag.typeExpression.type) : getContextualType(<ParenthesizedExpression>parent);
}
case SyntaxKind.JsxExpression:
return getContextualTypeForJsxExpression(<JsxExpression>parent);
case SyntaxKind.JsxAttribute:
@ -13689,12 +13669,14 @@ namespace ts {
(node.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node).operatorToken.kind === SyntaxKind.EqualsToken);
}
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode?: CheckMode): Type {
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined): Type {
const elements = node.elements;
let hasSpreadElement = false;
const elementTypes: Type[] = [];
const inDestructuringPattern = isAssignmentTarget(node);
for (const e of elements) {
const contextualType = getApparentTypeOfContextualType(node);
for (let index = 0; index < elements.length; index++) {
const e = elements[index];
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElement) {
// Given the following situation:
// var c: {};
@ -13716,7 +13698,8 @@ namespace ts {
}
}
else {
const type = checkExpressionForMutableLocation(e, checkMode);
const elementContextualType = getContextualTypeForElementExpression(contextualType, index);
const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType);
elementTypes.push(type);
}
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement;
@ -18305,9 +18288,13 @@ namespace ts {
return false;
}
function checkExpressionForMutableLocation(node: Expression, checkMode?: CheckMode): Type {
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode, contextualType?: Type): Type {
if (arguments.length === 2) {
contextualType = getContextualType(node);
}
const type = checkExpression(node, checkMode);
return isTypeAssertion(node) || isLiteralContextualType(getContextualType(node)) ? type : getWidenedLiteralType(type);
const shouldWiden = isTypeAssertion(node) || isLiteralContextualType(contextualType);
return shouldWiden ? type : getWidenedLiteralType(type);
}
function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type {
@ -18425,13 +18412,9 @@ namespace ts {
}
function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
if (isInJavaScriptFile(node) && node.jsDoc) {
const typecasts = flatMap(node.jsDoc, doc => filter(doc.tags, tag => tag.kind === SyntaxKind.JSDocTypeTag && !!(tag as JSDocTypeTag).typeExpression && !!(tag as JSDocTypeTag).typeExpression.type));
if (typecasts && typecasts.length) {
// We should have already issued an error if there were multiple type jsdocs
const cast = typecasts[0] as JSDocTypeTag;
return checkAssertionWorker(cast, cast.typeExpression.type, node.expression, checkMode);
}
const tag = isInJavaScriptFile(node) ? getJSDocTypeTag(node) : undefined;
if (tag) {
return checkAssertionWorker(tag, tag.typeExpression.type, node.expression, checkMode);
}
return checkExpression(node.expression, checkMode);
}

View File

@ -994,11 +994,6 @@ namespace ts {
/**
* Gets the owned, enumerable property keys of a map-like.
*
* NOTE: This is intended for use with MapLike<T> objects. For Map<T> objects, use
* Object.keys instead as it offers better performance.
*
* @param map A map-like.
*/
export function getOwnKeys<T>(map: MapLike<T>): string[] {
const keys: string[] = [];
@ -1011,6 +1006,17 @@ namespace ts {
return keys;
}
export function getOwnValues<T>(sparseArray: T[]): T[] {
const values: T[] = [];
for (const key in sparseArray) {
if (hasOwnProperty.call(sparseArray, key)) {
values.push(sparseArray[key]);
}
}
return values;
}
/** Shims `Array.from`. */
export function arrayFrom<T, U>(iterator: Iterator<T>, map: (t: T) => U): U[];
export function arrayFrom<T>(iterator: Iterator<T>): T[];

View File

@ -6149,11 +6149,14 @@ namespace ts {
}
// Parses out a JSDoc type expression.
/* @internal */
export function parseJSDocTypeExpression(): JSDocTypeExpression {
export function parseJSDocTypeExpression(): JSDocTypeExpression;
export function parseJSDocTypeExpression(requireBraces: true): JSDocTypeExpression | undefined;
export function parseJSDocTypeExpression(requireBraces?: boolean): JSDocTypeExpression | undefined {
const result = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
parseExpected(SyntaxKind.OpenBraceToken);
if (!parseExpected(SyntaxKind.OpenBraceToken) && requireBraces) {
return undefined;
}
result.type = doInsideOfContext(NodeFlags.JSDoc, parseType);
parseExpected(SyntaxKind.CloseBraceToken);
@ -6500,14 +6503,8 @@ namespace ts {
}
function tryParseTypeExpression(): JSDocTypeExpression | undefined {
return tryParse(() => {
skipWhitespace();
if (token() !== SyntaxKind.OpenBraceToken) {
return undefined;
}
return parseJSDocTypeExpression();
});
skipWhitespace();
return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
}
function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
@ -6616,7 +6613,7 @@ namespace ts {
const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, atToken.pos);
result.atToken = atToken;
result.tagName = tagName;
result.typeExpression = tryParseTypeExpression();
result.typeExpression = parseJSDocTypeExpression(/*mayBail*/ true);
return finishNode(result);
}

View File

@ -14,21 +14,29 @@ namespace ts {
return getSymbolWalker;
function getSymbolWalker(accept: (symbol: Symbol) => boolean = () => true): SymbolWalker {
const visitedTypes = createMap<Type>(); // Key is id as string
const visitedSymbols = createMap<Symbol>(); // Key is id as string
const visitedTypes: Type[] = []; // Sparse array from id to type
const visitedSymbols: Symbol[] = []; // Sparse array from id to symbol
return {
walkType: type => {
visitedTypes.clear();
visitedSymbols.clear();
visitType(type);
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
try {
visitType(type);
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
}
finally {
clear(visitedTypes);
clear(visitedSymbols);
}
},
walkSymbol: symbol => {
visitedTypes.clear();
visitedSymbols.clear();
visitSymbol(symbol);
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
try {
visitSymbol(symbol);
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
}
finally {
clear(visitedTypes);
clear(visitedSymbols);
}
},
};
@ -37,11 +45,10 @@ namespace ts {
return;
}
const typeIdString = type.id.toString();
if (visitedTypes.has(typeIdString)) {
if (visitedTypes[type.id]) {
return;
}
visitedTypes.set(typeIdString, type);
visitedTypes[type.id] = type;
// Reuse visitSymbol to visit the type's symbol,
// but be sure to bail on recuring into the type if accept declines the symbol.
@ -79,18 +86,9 @@ namespace ts {
}
}
function visitTypeList(types: Type[]): void {
if (!types) {
return;
}
for (let i = 0; i < types.length; i++) {
visitType(types[i]);
}
}
function visitTypeReference(type: TypeReference): void {
visitType(type.target);
visitTypeList(type.typeArguments);
forEach(type.typeArguments, visitType);
}
function visitTypeParameter(type: TypeParameter): void {
@ -98,7 +96,7 @@ namespace ts {
}
function visitUnionOrIntersectionType(type: UnionOrIntersectionType): void {
visitTypeList(type.types);
forEach(type.types, visitType);
}
function visitIndexType(type: IndexType): void {
@ -122,7 +120,7 @@ namespace ts {
if (signature.typePredicate) {
visitType(signature.typePredicate.type);
}
visitTypeList(signature.typeParameters);
forEach(signature.typeParameters, visitType);
for (const parameter of signature.parameters){
visitSymbol(parameter);
@ -133,8 +131,8 @@ namespace ts {
function visitInterfaceType(interfaceT: InterfaceType): void {
visitObjectType(interfaceT);
visitTypeList(interfaceT.typeParameters);
visitTypeList(getBaseTypes(interfaceT));
forEach(interfaceT.typeParameters, visitType);
forEach(getBaseTypes(interfaceT), visitType);
visitType(interfaceT.thisType);
}
@ -161,11 +159,11 @@ namespace ts {
if (!symbol) {
return;
}
const symbolIdString = getSymbolId(symbol).toString();
if (visitedSymbols.has(symbolIdString)) {
const symbolId = getSymbolId(symbol);
if (visitedSymbols[symbolId]) {
return;
}
visitedSymbols.set(symbolIdString, symbol);
visitedSymbols[symbolId] = symbol;
if (!accept(symbol)) {
return true;
}

View File

@ -4116,8 +4116,8 @@ namespace ts {
}
export interface CompilerHost extends ModuleResolutionHost {
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined;
getCancellationToken?(): CancellationToken;
getDefaultLibFileName(options: CompilerOptions): string;
getDefaultLibLocation?(): string;

View File

@ -321,6 +321,18 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node, includeTrivia);
}
/**
* Note: it is expected that the `nodeArray` and the `node` are within the same file.
* For example, searching for a `SourceFile` in a `SourceFile[]` wouldn't work.
*/
export function indexOfNode(nodeArray: ReadonlyArray<Node>, node: Node) {
return binarySearch(nodeArray, node, compareNodePos);
}
function compareNodePos({ pos: aPos }: Node, { pos: bPos}: Node) {
return aPos < bPos ? Comparison.LessThan : bPos < aPos ? Comparison.GreaterThan : Comparison.EqualTo;
}
/**
* Gets flags that control emit behavior of a node.
*/
@ -4091,9 +4103,14 @@ namespace ts {
return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag;
}
/** Gets the JSDoc type tag for the node if present */
/** Gets the JSDoc type tag for the node if present and valid */
export function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined {
return getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
// We should have already issued an error if there were multiple type jsdocs, so just use the first one.
const tag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
if (tag && tag.typeExpression && tag.typeExpression.type) {
return tag;
}
return undefined;
}
/**

View File

@ -44,7 +44,8 @@ namespace Harness.Parallel.Host {
console.log("Discovering tests...");
const discoverStart = +(new Date());
const { statSync }: { statSync(path: string): { size: number }; } = require("fs");
const tasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
let tasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
const newTasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
const perfData = readSavedPerfData();
let totalCost = 0;
let unknownValue: string | undefined;
@ -60,8 +61,10 @@ namespace Harness.Parallel.Host {
const hashedName = hashName(runner.kind(), file);
size = perfData[hashedName];
if (size === undefined) {
size = Number.MAX_SAFE_INTEGER;
size = 0;
unknownValue = hashedName;
newTasks.push({ runner: runner.kind(), file, size });
continue;
}
}
tasks.push({ runner: runner.kind(), file, size });
@ -69,6 +72,7 @@ namespace Harness.Parallel.Host {
}
}
tasks.sort((a, b) => a.size - b.size);
tasks = tasks.concat(newTasks);
// 1 fewer batches than threads to account for unittests running on the final thread
const batchCount = runners.length === 1 ? workerCount : workerCount - 1;
const packfraction = 0.9;
@ -174,7 +178,7 @@ namespace Harness.Parallel.Host {
let scheduledTotal = 0;
batcher: while (true) {
for (let i = 0; i < batchCount; i++) {
if (tasks.length === 0) {
if (tasks.length <= workerCount) { // Keep a small reserve even in the suboptimally packed case
console.log(`Suboptimal packing detected: no tests remain to be stolen. Reduce packing fraction from ${packfraction} to fix.`);
break batcher;
}
@ -213,7 +217,9 @@ namespace Harness.Parallel.Host {
worker.send({ type: "batch", payload });
}
else { // Unittest thread - send off just one test
worker.send({ type: "test", payload: tasks.pop() });
const payload = tasks.pop();
ts.Debug.assert(!!payload); // The reserve kept above should ensure there is always an initial task available, even in suboptimal scenarios
worker.send({ type: "test", payload });
}
}
}

View File

@ -139,6 +139,11 @@ namespace ts {
`/**
* @param
*/`);
parsesIncorrectly("noType",
`/**
* @type
*/`);
});
describe("parsesCorrectly", () => {
@ -148,12 +153,6 @@ namespace ts {
*/`);
parsesCorrectly("noType",
`/**
* @type
*/`);
parsesCorrectly("noReturnType",
`/**
* @return

View File

@ -53,28 +53,19 @@ namespace ts.formatting {
return res;
function advance(): void {
Debug.assert(scanner !== undefined, "Scanner should be present");
lastTokenInfo = undefined;
const isStarted = scanner.getStartPos() !== startPos;
if (isStarted) {
if (trailingTrivia) {
Debug.assert(trailingTrivia.length !== 0);
wasNewLine = lastOrUndefined(trailingTrivia).kind === SyntaxKind.NewLineTrivia;
}
else {
wasNewLine = false;
}
wasNewLine = trailingTrivia && lastOrUndefined(trailingTrivia)!.kind === SyntaxKind.NewLineTrivia;
}
else {
scanner.scan();
}
leadingTrivia = undefined;
trailingTrivia = undefined;
if (!isStarted) {
scanner.scan();
}
let pos = scanner.getStartPos();
// Read leading trivia and token
@ -94,25 +85,20 @@ namespace ts.formatting {
pos = scanner.getStartPos();
if (!leadingTrivia) {
leadingTrivia = [];
}
leadingTrivia.push(item);
leadingTrivia = append(leadingTrivia, item);
}
savedPos = scanner.getStartPos();
}
function shouldRescanGreaterThanToken(node: Node): boolean {
if (node) {
switch (node.kind) {
case SyntaxKind.GreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
case SyntaxKind.GreaterThanGreaterThanToken:
return true;
}
switch (node.kind) {
case SyntaxKind.GreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
case SyntaxKind.GreaterThanGreaterThanToken:
return true;
}
return false;
@ -134,7 +120,7 @@ namespace ts.formatting {
}
function shouldRescanJsxText(node: Node): boolean {
return node && node.kind === SyntaxKind.JsxText;
return node.kind === SyntaxKind.JsxText;
}
function shouldRescanSlashToken(container: Node): boolean {
@ -151,16 +137,7 @@ namespace ts.formatting {
}
function readTokenInfo(n: Node): TokenInfo {
Debug.assert(scanner !== undefined);
if (!isOnToken()) {
// scanner is not on the token (either advance was not called yet or scanner is already past the end position)
return {
leadingTrivia,
trailingTrivia: undefined,
token: undefined
};
}
Debug.assert(isOnToken());
// normally scanner returns the smallest available token
// check the kind of context node to determine if scanner should have more greedy behavior and consume more text.
@ -194,33 +171,7 @@ namespace ts.formatting {
scanner.scan();
}
let currentToken = scanner.getToken();
if (expectedScanAction === ScanAction.RescanGreaterThanToken && currentToken === SyntaxKind.GreaterThanToken) {
currentToken = scanner.reScanGreaterToken();
Debug.assert(n.kind === currentToken);
lastScanAction = ScanAction.RescanGreaterThanToken;
}
else if (expectedScanAction === ScanAction.RescanSlashToken && startsWithSlashToken(currentToken)) {
currentToken = scanner.reScanSlashToken();
Debug.assert(n.kind === currentToken);
lastScanAction = ScanAction.RescanSlashToken;
}
else if (expectedScanAction === ScanAction.RescanTemplateToken && currentToken === SyntaxKind.CloseBraceToken) {
currentToken = scanner.reScanTemplateToken();
lastScanAction = ScanAction.RescanTemplateToken;
}
else if (expectedScanAction === ScanAction.RescanJsxIdentifier) {
currentToken = scanner.scanJsxIdentifier();
lastScanAction = ScanAction.RescanJsxIdentifier;
}
else if (expectedScanAction === ScanAction.RescanJsxText) {
currentToken = scanner.reScanJsxToken();
lastScanAction = ScanAction.RescanJsxText;
}
else {
lastScanAction = ScanAction.Scan;
}
let currentToken = getNextToken(n, expectedScanAction);
const token: TextRangeWithKind = {
pos: scanner.getStartPos(),
@ -261,9 +212,47 @@ namespace ts.formatting {
return fixTokenKind(lastTokenInfo, n);
}
function isOnToken(): boolean {
Debug.assert(scanner !== undefined);
function getNextToken(n: Node, expectedScanAction: ScanAction): SyntaxKind {
const token = scanner.getToken();
lastScanAction = ScanAction.Scan;
switch (expectedScanAction) {
case ScanAction.RescanGreaterThanToken:
if (token === SyntaxKind.GreaterThanToken) {
lastScanAction = ScanAction.RescanGreaterThanToken;
const newToken = scanner.reScanGreaterToken();
Debug.assert(n.kind === newToken);
return newToken;
}
break;
case ScanAction.RescanSlashToken:
if (startsWithSlashToken(token)) {
lastScanAction = ScanAction.RescanSlashToken;
const newToken = scanner.reScanSlashToken();
Debug.assert(n.kind === newToken);
return newToken;
}
break;
case ScanAction.RescanTemplateToken:
if (token === SyntaxKind.CloseBraceToken) {
lastScanAction = ScanAction.RescanTemplateToken;
return scanner.reScanTemplateToken();
}
break;
case ScanAction.RescanJsxIdentifier:
lastScanAction = ScanAction.RescanJsxIdentifier;
return scanner.scanJsxIdentifier();
case ScanAction.RescanJsxText:
lastScanAction = ScanAction.RescanJsxText;
return scanner.reScanJsxToken();
case ScanAction.Scan:
break;
default:
Debug.assertNever(expectedScanAction);
}
return token;
}
function isOnToken(): boolean {
const current = lastTokenInfo ? lastTokenInfo.token.kind : scanner.getToken();
const startPos = lastTokenInfo ? lastTokenInfo.token.pos : scanner.getStartPos();
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);

View File

@ -226,7 +226,7 @@ namespace ts.textChanges {
Debug.fail("node is not a list element");
return this;
}
const index = containingList.indexOf(node);
const index = indexOfNode(containingList, node);
if (index < 0) {
return this;
}
@ -358,7 +358,7 @@ namespace ts.textChanges {
Debug.fail("node is not a list element");
return this;
}
const index = containingList.indexOf(after);
const index = indexOfNode(containingList, after);
if (index < 0) {
return this;
}

View File

@ -597,7 +597,7 @@ namespace ts {
}
const children = list.getChildren();
const listItemIndex = indexOf(children, node);
const listItemIndex = indexOfNode(children, node);
return {
listItemIndex,

View File

@ -1,9 +1,9 @@
=== tests/cases/compiler/declarationQuotedMembers.ts ===
export declare const mapped: { [K in 'a-b-c']: number }
>mapped : { a-b-c: number; }
>mapped : { "a-b-c": number; }
>K : K
export const example = mapped;
>example : { a-b-c: number; }
>mapped : { a-b-c: number; }
>example : { "a-b-c": number; }
>mapped : { "a-b-c": number; }

View File

@ -0,0 +1,7 @@
/// <reference path="fourslash.ts" />
// @allowJs: true
// @Filename: /a.js
////const x = /** @type {{ s: string }} */ ({ /**/ });
verify.completionsAt("", ["s", "x"]);