diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 5e6e753fff3d9..3acb430627981 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -126,7 +126,7 @@ namespace ts { let symbolCount = 0; let Symbol: { new (flags: SymbolFlags, name: string): Symbol }; - let classifiableNames: Map; + let classifiableNames: Set; const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; @@ -140,7 +140,7 @@ namespace ts { options = opts; languageVersion = getEmitScriptTarget(options); inStrictMode = !!file.externalModuleIndicator; - classifiableNames = createMap(); + classifiableNames = createSet(); symbolCount = 0; skipTransformFlagAggregation = isDeclarationFile(file); @@ -335,7 +335,7 @@ namespace ts { symbol = _getOrUpdate(symbolTable, name, name => createSymbol(SymbolFlags.None, name)); if (name && (includes & SymbolFlags.Classifiable)) { - _s(classifiableNames, name, name); + _add(classifiableNames, name); } if (symbol.flags & excludes) { @@ -2089,7 +2089,7 @@ namespace ts { bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName); // Add name of class expression into the map for semantic classifier if (node.name) { - _s(classifiableNames, node.name.text, node.name.text); + _add(classifiableNames, node.name.text); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 84454b3fb2e05..675b50c032815 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7620,7 +7620,7 @@ namespace ts { let targetStack: Type[]; let depth = 0; let inferiority = 0; - const visited = createMap(); + const visited = createSet(); inferFromTypes(originalSource, originalTarget); function isInProcess(source: Type, target: Type) { @@ -7756,10 +7756,10 @@ namespace ts { return; } const key = source.id + "," + target.id; - if (_g(visited, key)) { + if (_setHas(visited, key)) { return; } - _s(visited, key, true); + _add(visited, key); if (depth === 0) { sourceStack = []; targetStack = []; @@ -10377,7 +10377,7 @@ namespace ts { } } - function checkJsxAttribute(node: JsxAttribute, elementAttributesType: Type, nameTable: Map) { + function checkJsxAttribute(node: JsxAttribute, elementAttributesType: Type, nameTable: Set) { let correspondingPropType: Type = undefined; // Look up the corresponding property for this attribute @@ -10416,24 +10416,24 @@ namespace ts { checkTypeAssignableTo(exprType, correspondingPropType, node); } - _s(nameTable, node.name.text, true); + _add(nameTable, node.name.text); return exprType; } - function checkJsxSpreadAttribute(node: JsxSpreadAttribute, elementAttributesType: Type, nameTable: Map) { + function checkJsxSpreadAttribute(node: JsxSpreadAttribute, elementAttributesType: Type, nameTable: Set) { const type = checkExpression(node.expression); const props = getPropertiesOfType(type); for (const prop of props) { // Is there a corresponding property in the element attributes type? Skip checking of properties // that have already been assigned to, as these are not actually pushed into the resulting type - if (!_g(nameTable, prop.name)) { + if (!_setHas(nameTable, prop.name)) { const targetPropSym = getPropertyOfType(elementAttributesType, prop.name); if (targetPropSym) { const msg = chainDiagnosticMessages(undefined, Diagnostics.Property_0_of_JSX_spread_attribute_is_not_assignable_to_target_property, prop.name); checkTypeAssignableTo(getTypeOfSymbol(prop), getTypeOfSymbol(targetPropSym), node, undefined, msg); } - _s(nameTable, prop.name, true); + _add(nameTable, prop.name); } } return type; @@ -10749,7 +10749,7 @@ namespace ts { const targetAttributesType = getJsxElementAttributesType(node); - const nameTable = createMap(); + const nameTable = createSet(); // Process this array in right-to-left order so we know which // attributes (mostly from spreads) are being overwritten and // thus should have their types ignored @@ -10773,7 +10773,7 @@ namespace ts { const targetProperties = getPropertiesOfType(targetAttributesType); for (let i = 0; i < targetProperties.length; i++) { if (!(targetProperties[i].flags & SymbolFlags.Optional) && - !_g(nameTable, targetProperties[i].name)) { + !_setHas(nameTable, targetProperties[i].name)) { error(node, Diagnostics.Property_0_is_missing_in_type_1, targetProperties[i].name, typeToString(targetAttributesType)); } @@ -14229,7 +14229,7 @@ namespace ts { } function checkObjectTypeForDuplicateDeclarations(node: TypeLiteralNode | InterfaceDeclaration) { - const names = createMap(); + const names = createSet(); for (const member of node.members) { if (member.kind == SyntaxKind.PropertySignature) { let memberName: string; @@ -14243,12 +14243,12 @@ namespace ts { continue; } - if (_g(names, memberName)) { + if (_setHas(names, memberName)) { error(member.symbol.valueDeclaration.name, Diagnostics.Duplicate_identifier_0, memberName); error(member.name, Diagnostics.Duplicate_identifier_0, memberName); } else { - _s(names, memberName, true); + _add(names, memberName); } } } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 542f3b8a2ee22..96048e498ac74 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -975,9 +975,6 @@ namespace ts { function convertOptionsFromJson(optionDeclarations: CommandLineOption[], jsonOptions: any, basePath: string, defaultOptions: CompilerOptions | TypingOptions, diagnosticMessage: DiagnosticMessage, errors: Diagnostic[]) { - //kill - checkNotNativeMap(jsonOptions); - if (!jsonOptions) { return; } diff --git a/src/compiler/dataStructures.ts b/src/compiler/dataStructures.ts index 9fc206156b725..acb7226f666c4 100644 --- a/src/compiler/dataStructures.ts +++ b/src/compiler/dataStructures.ts @@ -59,7 +59,7 @@ namespace ts { } declare const Map: { new(): NativeMap } | undefined; - const realMaps = typeof Map !== "undefined"; //false; + const realMaps = typeof Map !== "undefined"; const createObject = Object.create; const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -92,8 +92,6 @@ namespace ts { return map; } - //PRIMITIVE OPERATIONS: Need a different strategy for real map vs {} - export const _g: (map: Map, key: string) => T = realMaps ? (map: NativeMap, key: string) => map.get(key) : (map: MapLike, key: string) => map[key]; @@ -139,7 +137,6 @@ namespace ts { export const _find: (map: Map, f: (key: string, value: T) => U | undefined) => U | undefined = realMaps ? (map: NativeMap, f: (key: string, value: T) => U | undefined) => { - //use forEach? const iter = map.entries(); while (true) { const { value: pair, done } = iter.next(); @@ -321,11 +318,6 @@ namespace ts { } return undefined; }; - - //kill - export function checkNotNativeMap(value: MapLike) { - Debug.assert(!(value instanceof Map)); - } } @@ -366,12 +358,18 @@ namespace ts { * @param source A map from which properties should be copied. * @param target A map to which properties should be copied. */ + //rename : "entries", not "properties" export function copyMapPropertiesFromTo(source: Map, target: Map): void { _each(source, (key, value) => { _s(target, key, value); }); } + //move + export function copySetValuesFromTo(source: Set, target: Set): void { + _eachInSet(source, value => _add(target, value)); + } + //kill? /** * Reduce the properties of a map. @@ -497,16 +495,39 @@ namespace ts { declare const Set: { new(): NativeSet } | undefined; const realSets = typeof Set !== "undefined"; + /*interface StringSetModule { + createSet(): Set + add(set: Set, value: string): string; + } + const StringSet: StringSetModule = realSets ? + { + createSet: () => new Set(), + add(set: NativeSet, value: string) { + set.add(value); + return value; + } + } + : + { + createSet: () => createDictionaryModeObject(), + add(set: SetLike, value: string) { + set[value] = true; + return value; + } + }*/ + export const createSet: () => Set = realSets ? () => new Set() : () => createDictionaryModeObject(); - export const _add: (set: Set, value: string) => void = realSets + export const _add: (set: Set, value: string) => string = realSets ? (set: NativeSet, value: string) => { set.add(value); + return value; } : (set: SetLike, value: string) => { set[value] = true; + return value; } export const _setHas: (set: Set, value: string) => boolean = realSets @@ -537,15 +558,9 @@ namespace ts { for (const value in set) f(value); } - - //todo: more iteration helpers } - - - - -//MAPLIKE CRAP +//MAPLIKE /* @internal */ namespace ts { const hasOwnProperty = Object.prototype.hasOwnProperty; //neater @@ -570,7 +585,6 @@ namespace ts { * @param key A property key. */ export function hasProperty(map: MapLike, key: string): boolean { - checkNotNativeMap(map); return hasOwnProperty.call(map, key); } @@ -584,7 +598,6 @@ namespace ts { * @param key A property key. */ export function getProperty(map: MapLike, key: string): T | undefined { - checkNotNativeMap(map); return hasOwnProperty.call(map, key) ? map[key] : undefined; } @@ -597,7 +610,6 @@ namespace ts { * @param map A map-like. */ export function getOwnKeys(map: MapLike): string[] { - checkNotNativeMap(map); const keys: string[] = []; for (const key in map) if (hasOwnProperty.call(map, key)) { keys.push(key); @@ -609,9 +621,7 @@ namespace ts { export function assign, T2>(t: T1, arg1: T2): T1 & T2; export function assign>(t: T1, ...args: any[]): any; export function assign>(t: T1, ...args: any[]) { - checkNotNativeMap(t); for (const arg of args) { - checkNotNativeMap(arg); for (const p of getOwnKeys(arg)) { t[p] = arg[p]; } @@ -630,7 +640,6 @@ namespace ts { * @param initial The initial value for the reduction. */ export function reduceOwnProperties(map: MapLike, callback: (aggregate: U, value: T, key: string) => U, initial: U): U { - checkNotNativeMap(map); let result = initial; for (const key in map) if (hasOwnProperty.call(map, key)) { result = callback(result, map[key], String(key)); @@ -645,8 +654,6 @@ namespace ts { * @param right A map-like whose properties should be compared. */ export function equalOwnProperties(left: MapLike, right: MapLike, equalityComparer?: (left: T, right: T) => boolean) { - checkNotNativeMap(left); - checkNotNativeMap(right); if (left === right) return true; if (!left || !right) return false; for (const key in left) if (hasOwnProperty.call(left, key)) { @@ -660,8 +667,6 @@ namespace ts { } export function extend(first: T1 , second: T2): T1 & T2 { - checkNotNativeMap(first); - checkNotNativeMap(second); const result: T1 & T2 = {}; for (const id in second) if (hasOwnProperty.call(second, id)) { (result as any)[id] = (second as any)[id]; diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 37b032ea5a3cd..f88144b8ad287 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -75,7 +75,7 @@ namespace ts { // and we could be collecting these paths from multiple files into single one with --out option let referencesOutput = ""; - let usedTypeDirectiveReferences: Map; + let usedTypeDirectiveReferences: Set; // Emit references corresponding to each file const emittedReferencedFiles: SourceFile[] = []; @@ -156,7 +156,7 @@ namespace ts { }); if (usedTypeDirectiveReferences) { - _eachKey(usedTypeDirectiveReferences, directive => { + _eachInSet(usedTypeDirectiveReferences, directive => { referencesOutput += `/// ${newLine}`; }); } @@ -267,11 +267,11 @@ namespace ts { } if (!usedTypeDirectiveReferences) { - usedTypeDirectiveReferences = createMap(); + usedTypeDirectiveReferences = createSet(); } for (const directive of typeReferenceDirectives) { - if (!_has(usedTypeDirectiveReferences, directive)) { - _s(usedTypeDirectiveReferences, directive, directive); + if (!_setHas(usedTypeDirectiveReferences, directive)) { + _add(usedTypeDirectiveReferences, directive); } } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index dd7c14bb4fd57..48bff388b075f 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -218,7 +218,7 @@ const _super = (function (geti, seti) { let nodeIdToGeneratedName: string[]; let autoGeneratedIdToGeneratedName: string[]; - let generatedNameSet: Map; + let generatedNameSet: Set; let tempFlags: TempFlags; let currentSourceFile: SourceFile; let currentText: string; @@ -296,7 +296,7 @@ const _super = (function (geti, seti) { sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit); nodeIdToGeneratedName = []; autoGeneratedIdToGeneratedName = []; - generatedNameSet = createMap(); + generatedNameSet = createSet(); isOwnFileEmit = !isBundledEmit; // Emit helpers from all the files @@ -2704,7 +2704,7 @@ const _super = (function (geti, seti) { function isUniqueName(name: string): boolean { return !resolver.hasGlobalName(name) && !_has(currentFileIdentifiers, name) && - !_has(generatedNameSet, name); + !_setHas(generatedNameSet, name); } function isUniqueLocalName(name: string, container: Node): boolean { @@ -2760,7 +2760,7 @@ const _super = (function (geti, seti) { while (true) { const generatedName = baseName + i; if (isUniqueName(generatedName)) { - return _s(generatedNameSet, generatedName, generatedName); + return _add(generatedNameSet, generatedName); } i++; } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index dcbdbf842e0a3..534bcb0bf8f57 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -863,7 +863,7 @@ namespace ts { } export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost { - const existingDirectories = createMap(); + const existingDirectories = createSet(); function getCanonicalFileName(fileName: string): string { // if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form. @@ -895,11 +895,11 @@ namespace ts { } function directoryExists(directoryPath: string): boolean { - if (_has(existingDirectories, directoryPath)) { + if (_setHas(existingDirectories, directoryPath)) { return true; } if (sys.directoryExists(directoryPath)) { - _s(existingDirectories, directoryPath, true); + _add(existingDirectories, directoryPath); return true; } return false; @@ -1114,7 +1114,7 @@ namespace ts { let commonSourceDirectory: string; let diagnosticsProducingTypeChecker: TypeChecker; let noDiagnosticsTypeChecker: TypeChecker; - let classifiableNames: Map; + let classifiableNames: Set; let resolvedTypeReferenceDirectives = createMap(); let fileProcessingDiagnostics = createDiagnosticCollection(); @@ -1258,14 +1258,15 @@ namespace ts { return commonSourceDirectory; } - function getClassifiableNames() { + function getClassifiableNames(): Set { if (!classifiableNames) { // Initialize a checker so that all our files are bound. getTypeChecker(); - classifiableNames = createMap(); + classifiableNames = createSet(); for (const sourceFile of files) { - copyMapPropertiesFromTo(sourceFile.classifiableNames, classifiableNames); + //copyMapPropertiesFromTo(sourceFile.classifiableNames, classifiableNames); + copySetValuesFromTo(sourceFile.classifiableNames, classifiableNames); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4213764a6fe10..938c3a9165369 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1774,7 +1774,7 @@ namespace ts { // Stores a line map for the file. // This field should never be used directly to obtain line map, use getLineMap function instead. /* @internal */ lineMap: number[]; - /* @internal */ classifiableNames?: Map; + /* @internal */ classifiableNames?: Set; // Stores a mapping 'external module reference text' -> 'resolved file name' | undefined // It is used to resolve module names in the checker. // Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead @@ -1862,7 +1862,7 @@ namespace ts { // language service). /* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker; - /* @internal */ getClassifiableNames(): Map; + /* @internal */ getClassifiableNames(): Set; /* @internal */ getNodeCount(): number; /* @internal */ getIdentifierCount(): number; diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index 4825333372492..3f1e96b2cbe6d 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -10,11 +10,11 @@ namespace ts { const map = arrayToMap(files, f => f.name); if (hasDirectoryExists) { - const directories = createMap(); + const directories = createSet(); for (const f of files) { let name = getDirectoryPath(f.name); while (true) { - _s(directories, name, name); + _add(directories, name); const baseName = getDirectoryPath(name); if (baseName === name) { break; @@ -25,10 +25,10 @@ namespace ts { return { readFile, directoryExists: path => { - return _has(directories, path); + return _setHas(directories, path); }, fileExists: path => { - assert.isTrue(_has(directories, getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`); + assert.isTrue(_setHas(directories, getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`); return _has(map, path); } }; diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 17229b3cc356a..71fdf99e83122 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -462,7 +462,7 @@ namespace ts { } /* @internal */ - export function getSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Map, span: TextSpan): ClassifiedSpan[] { + export function getSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Set, span: TextSpan): ClassifiedSpan[] { return convertClassifications(getEncodedSemanticClassifications(typeChecker, cancellationToken, sourceFile, classifiableNames, span)); } @@ -487,7 +487,7 @@ namespace ts { } /* @internal */ - export function getEncodedSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Map, span: TextSpan): Classifications { + export function getEncodedSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Set, span: TextSpan): Classifications { const result: number[] = []; processNode(sourceFile); @@ -557,7 +557,7 @@ namespace ts { // Only bother calling into the typechecker if this is an identifier that // could possibly resolve to a type name. This makes classification run // in a third of the time it would normally take. - if (_g(classifiableNames, identifier.text)) { + if (_setHas(classifiableNames, identifier.text)) { const symbol = typeChecker.getSymbolAtLocation(node); if (symbol) { const type = classifySymbol(symbol, getMeaningFromLocation(node)); diff --git a/src/services/completions.ts b/src/services/completions.ts index c44bf628e20db..6296799725e9c 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -58,7 +58,7 @@ namespace ts.Completions { return { isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation || isSourceFileJavaScript(sourceFile), entries }; - function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map): CompletionEntry[] { + function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Set): CompletionEntry[] { const entries: CompletionEntry[] = []; _each(getNameTable(sourceFile), (name, nameTablePosition) => { @@ -67,8 +67,8 @@ namespace ts.Completions { return; } - if (!_g(uniqueNames, name)) { - _s(uniqueNames, name, name); + if (!_setHas(uniqueNames, name)) { + _add(uniqueNames, name); const displayName = getCompletionEntryDisplayName(unescapeIdentifier(name), compilerOptions.target, /*performCharacterChecks*/ true); if (displayName) { const entry = { @@ -111,17 +111,17 @@ namespace ts.Completions { } - function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map { + function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Set { const start = timestamp(); - const uniqueNames = createMap(); + const uniqueNames = createSet(); if (symbols) { for (const symbol of symbols) { const entry = createCompletionEntry(symbol, location, performCharacterChecks); if (entry) { const id = escapeIdentifier(entry.name); - if (!_g(uniqueNames, id)) { + if (!_setHas(uniqueNames, id)) { entries.push(entry); - _s(uniqueNames, id, id); + _add(uniqueNames, id); } } } diff --git a/src/services/jsTyping.ts b/src/services/jsTyping.ts index 986c6f2cfc4b4..a88329a5c2f40 100644 --- a/src/services/jsTyping.ts +++ b/src/services/jsTyping.ts @@ -15,6 +15,7 @@ namespace ts.JsTyping { interface PackageJson { _requiredBy?: string[]; + //Is this a real Mpa, or a MapLike? dependencies?: Map; devDependencies?: Map; name?: string;