Skip to content

Commit

Permalink
Merge branch 'master' into add-unmeasurable-variance-kind
Browse files Browse the repository at this point in the history
  • Loading branch information
weswigham committed May 3, 2019
2 parents 6a9e337 + fc88a1c commit a7fc378
Show file tree
Hide file tree
Showing 228 changed files with 6,367 additions and 875 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -7,7 +7,7 @@

[![Join the chat at https://gitter.im/Microsoft/TypeScript](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Microsoft/TypeScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

[TypeScript](https://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types to JavaScript that support tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](https://www.typescriptlang.org/play/), and stay up to date via [our blog](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescriptlang).
[TypeScript](https://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types to JavaScript that support tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](https://www.typescriptlang.org/play/), and stay up to date via [our blog](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescript).

## Installing

Expand Down
507 changes: 387 additions & 120 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

120 changes: 78 additions & 42 deletions src/compiler/commandLineParser.ts
Expand Up @@ -45,6 +45,7 @@ namespace ts {
["es2018.promise", "lib.es2018.promise.d.ts"],
["es2018.regexp", "lib.es2018.regexp.d.ts"],
["es2019.array", "lib.es2019.array.d.ts"],
["es2019.object", "lib.es2019.object.d.ts"],
["es2019.string", "lib.es2019.string.d.ts"],
["es2019.symbol", "lib.es2019.symbol.d.ts"],
["es2020.string", "lib.es2020.string.d.ts"],
Expand Down Expand Up @@ -218,6 +219,7 @@ namespace ts {
}),
affectsSourceFile: true,
affectsModuleResolution: true,
affectsEmit: true,
paramType: Diagnostics.VERSION,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
Expand Down Expand Up @@ -1345,7 +1347,12 @@ namespace ts {
/**
* Reads the config file, reports errors if any and exits if the config file cannot be found
*/
export function getParsedCommandLineOfConfigFile(configFileName: string, optionsToExtend: CompilerOptions, host: ParseConfigFileHost): ParsedCommandLine | undefined {
export function getParsedCommandLineOfConfigFile(
configFileName: string,
optionsToExtend: CompilerOptions,
host: ParseConfigFileHost,
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
): ParsedCommandLine | undefined {
let configFileText: string | undefined;
try {
configFileText = host.readFile(configFileName);
Expand All @@ -1366,7 +1373,16 @@ namespace ts {
result.path = toPath(configFileName, cwd, createGetCanonicalFileName(host.useCaseSensitiveFileNames));
result.resolvedPath = result.path;
result.originalFileName = result.fileName;
return parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd));
return parseJsonSourceFileConfigFileContent(
result,
host,
getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd),
optionsToExtend,
getNormalizedAbsolutePath(configFileName, cwd),
/*resolutionStack*/ undefined,
/*extraFileExtension*/ undefined,
extendedConfigCache
);
}

/**
Expand Down Expand Up @@ -1969,8 +1985,8 @@ namespace ts {
* @param basePath A root directory to resolve relative path entries in the config
* file to. e.g. outDir
*/
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ParsedCommandLine {
return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions);
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<FileExtensionInfo>, extendedConfigCache?: Map<ExtendedConfigCacheEntry>): ParsedCommandLine {
return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache);
}

/**
Expand All @@ -1980,8 +1996,8 @@ namespace ts {
* @param basePath A root directory to resolve relative path entries in the config
* file to. e.g. outDir
*/
export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ParsedCommandLine {
return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions);
export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<FileExtensionInfo>, extendedConfigCache?: Map<ExtendedConfigCacheEntry>): ParsedCommandLine {
return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache);
}

/*@internal*/
Expand Down Expand Up @@ -2020,11 +2036,12 @@ namespace ts {
configFileName?: string,
resolutionStack: Path[] = [],
extraFileExtensions: ReadonlyArray<FileExtensionInfo> = [],
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
): ParsedCommandLine {
Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined));
const errors: Diagnostic[] = [];

const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors);
const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors, extendedConfigCache);
const { raw } = parsedConfig;
const options = extend(existingOptions, parsedConfig.options || {});
options.configFilePath = configFileName && normalizeSlashes(configFileName);
Expand Down Expand Up @@ -2172,7 +2189,7 @@ namespace ts {
return existingErrors !== configParseDiagnostics.length;
}

interface ParsedTsconfig {
export interface ParsedTsconfig {
raw: any;
options?: CompilerOptions;
typeAcquisition?: TypeAcquisition;
Expand All @@ -2191,13 +2208,14 @@ namespace ts {
* It does *not* resolve the included files.
*/
function parseConfig(
json: any,
sourceFile: TsConfigSourceFile | undefined,
host: ParseConfigHost,
basePath: string,
configFileName: string | undefined,
resolutionStack: string[],
errors: Push<Diagnostic>,
json: any,
sourceFile: TsConfigSourceFile | undefined,
host: ParseConfigHost,
basePath: string,
configFileName: string | undefined,
resolutionStack: string[],
errors: Push<Diagnostic>,
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
): ParsedTsconfig {
basePath = normalizeSlashes(basePath);
const resolvedPath = getNormalizedAbsolutePath(configFileName || "", basePath);
Expand All @@ -2214,7 +2232,7 @@ namespace ts {
if (ownConfig.extendedConfigPath) {
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
resolutionStack = resolutionStack.concat([resolvedPath]);
const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors, extendedConfigCache);
if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) {
const baseRaw = extendedConfig.raw;
const raw = ownConfig.raw;
Expand Down Expand Up @@ -2358,47 +2376,65 @@ namespace ts {
return undefined;
}

export interface ExtendedConfigCacheEntry {
extendedResult: TsConfigSourceFile;
extendedConfig: ParsedTsconfig | undefined;
}

function getExtendedConfig(
sourceFile: TsConfigSourceFile | undefined,
extendedConfigPath: string,
host: ParseConfigHost,
basePath: string,
resolutionStack: string[],
errors: Push<Diagnostic>,
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
): ParsedTsconfig | undefined {
const extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
const path = host.useCaseSensitiveFileNames ? extendedConfigPath : toLowerCase(extendedConfigPath);
let value: ExtendedConfigCacheEntry | undefined;
let extendedResult: TsConfigSourceFile;
let extendedConfig: ParsedTsconfig | undefined;
if (extendedConfigCache && (value = extendedConfigCache.get(path))) {
({ extendedResult, extendedConfig } = value);
}
else {
extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
if (!extendedResult.parseDiagnostics.length) {
const extendedDirname = getDirectoryPath(extendedConfigPath);
extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
getBaseFileName(extendedConfigPath), resolutionStack, errors, extendedConfigCache);

if (isSuccessfulParsedTsconfig(extendedConfig)) {
// Update the paths to reflect base path
const relativeDifference = convertToRelativePath(extendedDirname, basePath, identity);
const updatePath = (path: string) => isRootedDiskPath(path) ? path : combinePaths(relativeDifference, path);
const mapPropertiesInRawIfNotUndefined = (propertyName: string) => {
if (raw[propertyName]) {
raw[propertyName] = map(raw[propertyName], updatePath);
}
};

const { raw } = extendedConfig;
mapPropertiesInRawIfNotUndefined("include");
mapPropertiesInRawIfNotUndefined("exclude");
mapPropertiesInRawIfNotUndefined("files");
}
}
if (extendedConfigCache) {
extendedConfigCache.set(path, { extendedResult, extendedConfig });
}
}
if (sourceFile) {
sourceFile.extendedSourceFiles = [extendedResult.fileName];
if (extendedResult.extendedSourceFiles) {
sourceFile.extendedSourceFiles.push(...extendedResult.extendedSourceFiles);
}
}
if (extendedResult.parseDiagnostics.length) {
errors.push(...extendedResult.parseDiagnostics);
return undefined;
}

const extendedDirname = getDirectoryPath(extendedConfigPath);
const extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
getBaseFileName(extendedConfigPath), resolutionStack, errors);
if (sourceFile && extendedResult.extendedSourceFiles) {
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles);
}

if (isSuccessfulParsedTsconfig(extendedConfig)) {
// Update the paths to reflect base path
const relativeDifference = convertToRelativePath(extendedDirname, basePath, identity);
const updatePath = (path: string) => isRootedDiskPath(path) ? path : combinePaths(relativeDifference, path);
const mapPropertiesInRawIfNotUndefined = (propertyName: string) => {
if (raw[propertyName]) {
raw[propertyName] = map(raw[propertyName], updatePath);
}
};

const { raw } = extendedConfig;
mapPropertiesInRawIfNotUndefined("include");
mapPropertiesInRawIfNotUndefined("exclude");
mapPropertiesInRawIfNotUndefined("files");
}

return extendedConfig;
return extendedConfig!;
}

function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Push<Diagnostic>): boolean {
Expand Down
29 changes: 27 additions & 2 deletions src/compiler/core.ts
Expand Up @@ -1400,8 +1400,8 @@ namespace ts {
/** Shims `Array.from`. */
export function arrayFrom<T, U>(iterator: Iterator<T> | IterableIterator<T>, map: (t: T) => U): U[];
export function arrayFrom<T>(iterator: Iterator<T> | IterableIterator<T>): T[];
export function arrayFrom(iterator: Iterator<any> | IterableIterator<any>, map?: (t: any) => any): any[] {
const result: any[] = [];
export function arrayFrom<T, U>(iterator: Iterator<T> | IterableIterator<T>, map?: (t: T) => U): (T | U)[] {
const result: (T | U)[] = [];
for (let { value, done } = iterator.next(); !done; { value, done } = iterator.next()) {
result.push(map ? map(value) : value);
}
Expand Down Expand Up @@ -2284,4 +2284,29 @@ namespace ts {
}
return result;
}

export function cartesianProduct<T>(arrays: readonly T[][]) {
const result: T[][] = [];
cartesianProductWorker(arrays, result, /*outer*/ undefined, 0);
return result;
}

function cartesianProductWorker<T>(arrays: readonly (readonly T[])[], result: (readonly T[])[], outer: readonly T[] | undefined, index: number) {
for (const element of arrays[index]) {
let inner: T[];
if (outer) {
inner = outer.slice();
inner.push(element);
}
else {
inner = [element];
}
if (index === arrays.length - 1) {
result.push(inner);
}
else {
cartesianProductWorker(arrays, result, inner, index + 1);
}
}
}
}
23 changes: 21 additions & 2 deletions src/compiler/diagnosticMessages.json
Expand Up @@ -1035,6 +1035,10 @@
"category": "Error",
"code": 1355
},
"Did you mean to mark this function as 'async'?": {
"category": "Error",
"code": 1356
},

"Duplicate identifier '{0}'.": {
"category": "Error",
Expand Down Expand Up @@ -2959,7 +2963,7 @@
"category": "Error",
"code": 4104
},

"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001
Expand Down Expand Up @@ -3096,6 +3100,10 @@
"category": "Error",
"code": 5074
},
"'{0}' is assignable to the constraint of type '{1}', but '{1}' could be instantiated with a different subtype of constraint '{2}'.": {
"category": "Error",
"code": 5075
},

"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
Expand Down Expand Up @@ -4272,7 +4280,10 @@
"category": "Error",
"code": 7051
},

"Element implicitly has an 'any' type because type '{0}' has no index signature. Did you mean to call '{1}' ?": {
"category": "Error",
"code": 7052
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
Expand Down Expand Up @@ -4954,5 +4965,13 @@
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer." :{
"category": "Error",
"code": 18004
},
"Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '[\"constructor\"]()' to write a method.": {
"category": "Error",
"code": 18005
},
"Classes may not have a field named 'constructor'.": {
"category": "Error",
"code": 18006
}
}
2 changes: 1 addition & 1 deletion src/compiler/factory.ts
Expand Up @@ -2189,7 +2189,7 @@ namespace ts {
}

/* @internal */
export function createJSDocTypeTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocTypeTag {
export function createJSDocTypeTag(typeExpression: JSDocTypeExpression, comment?: string): JSDocTypeTag {
const tag = createJSDocTag<JSDocTypeTag>(SyntaxKind.JSDocTypeTag, "type");
tag.typeExpression = typeExpression;
tag.comment = comment;
Expand Down
21 changes: 3 additions & 18 deletions src/compiler/parser.ts
Expand Up @@ -6855,7 +6855,7 @@ namespace ts {
}

function parseReturnTag(start: number, tagName: Identifier): JSDocReturnTag {
if (forEach(tags, t => t.kind === SyntaxKind.JSDocReturnTag)) {
if (some(tags, isJSDocReturnTag)) {
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
}

Expand All @@ -6866,7 +6866,7 @@ namespace ts {
}

function parseTypeTag(start: number, tagName: Identifier): JSDocTypeTag {
if (forEach(tags, t => t.kind === SyntaxKind.JSDocTypeTag)) {
if (some(tags, isJSDocTypeTag)) {
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
}

Expand Down Expand Up @@ -7782,24 +7782,9 @@ namespace ts {

/*@internal*/
export function processCommentPragmas(context: PragmaContext, sourceText: string): void {
const triviaScanner = createScanner(context.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText);
const pragmas: PragmaPseudoMapEntry[] = [];

// Keep scanning all the leading trivia in the file until we get to something that
// isn't trivia. Any single line comment will be analyzed to see if it is a
// reference comment.
while (true) {
const kind = triviaScanner.scan();
if (!isTrivia(kind)) {
break;
}

const range = {
kind: <SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia>triviaScanner.getToken(),
pos: triviaScanner.getTokenPos(),
end: triviaScanner.getTextPos(),
};

for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) {
const comment = sourceText.substring(range.pos, range.end);
extractPragmas(pragmas, range, comment);
}
Expand Down

0 comments on commit a7fc378

Please sign in to comment.