diff --git a/Gulpfile.ts b/Gulpfile.ts
index 3d4bae39a32..296e374a53f 100644
--- a/Gulpfile.ts
+++ b/Gulpfile.ts
@@ -2,6 +2,7 @@
import * as cp from "child_process";
import * as path from "path";
import * as fs from "fs";
+import child_process = require("child_process");
import originalGulp = require("gulp");
import helpMaker = require("gulp-help");
import runSequence = require("run-sequence");
@@ -416,7 +417,7 @@ gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
file.path = nodeDefinitionsFile;
return content + "\r\nexport = ts;";
}))
- .pipe(gulp.dest(".")),
+ .pipe(gulp.dest("src/services")),
completedDts.pipe(clone())
.pipe(insert.transform((content, file) => {
file.path = nodeStandaloneDefinitionsFile;
@@ -477,12 +478,12 @@ gulp.task(tsserverLibraryFile, false, [servicesFile], (done) => {
return merge2([
js.pipe(prependCopyright())
.pipe(sourcemaps.write("."))
- .pipe(gulp.dest(".")),
+ .pipe(gulp.dest("src/server")),
dts.pipe(prependCopyright(/*outputCopyright*/true))
.pipe(insert.transform((content) => {
return content + "\r\nexport = ts;\r\nexport as namespace ts;";
}))
- .pipe(gulp.dest("."))
+ .pipe(gulp.dest("src/server"))
]);
});
@@ -749,7 +750,7 @@ gulp.task("browserify", "Runs browserify on run.js to produce a file suitable fo
const originalMap = file.sourceMap;
const prebundledContent = file.contents.toString();
// Make paths absolute to help sorcery deal with all the terrible paths being thrown around
- originalMap.sources = originalMap.sources.map(s => path.resolve(s));
+ originalMap.sources = originalMap.sources.map(s => path.resolve(path.join("src/harness", s)));
// intoStream (below) makes browserify think the input file is named this, so this is what it puts in the sourcemap
originalMap.file = "built/local/_stream_0.js";
@@ -960,7 +961,7 @@ gulp.task("update-sublime", "Updates the sublime plugin's tsserver", ["local", s
});
gulp.task("build-rules", "Compiles tslint rules to js", () => {
- const settings: tsc.Settings = getCompilerSettings({ module: "commonjs" }, /*useBuiltCompiler*/ false);
+ const settings: tsc.Settings = getCompilerSettings({ module: "commonjs", "lib": ["es6"] }, /*useBuiltCompiler*/ false);
const dest = path.join(builtLocalDirectory, "tslint");
return gulp.src("scripts/tslint/**/*.ts")
.pipe(newer({
@@ -1019,40 +1020,16 @@ function spawnLintWorker(files: {path: string}[], callback: (failures: number) =
}
gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: --f[iles]=regex", ["build-rules"], () => {
- const fileMatcher = RegExp(cmdLineOptions["files"]);
if (fold.isTravis()) console.log(fold.start("lint"));
-
- let files: {stat: fs.Stats, path: string}[] = [];
- return gulp.src(lintTargets, { read: false })
- .pipe(through2.obj((chunk, enc, cb) => {
- files.push(chunk);
- cb();
- }, (cb) => {
- files = files.filter(file => fileMatcher.test(file.path)).sort((filea, fileb) => filea.stat.size - fileb.stat.size);
- const workerCount = cmdLineOptions["workers"];
- for (let i = 0; i < workerCount; i++) {
- spawnLintWorker(files, finished);
- }
-
- let completed = 0;
- let failures = 0;
- function finished(fails) {
- completed++;
- failures += fails;
- if (completed === workerCount) {
- if (fold.isTravis()) console.log(fold.end("lint"));
- if (failures > 0) {
- throw new Error(`Linter errors: ${failures}`);
- }
- else {
- cb();
- }
- }
- }
- }));
+ const fileMatcher = cmdLineOptions["files"];
+ const files = fileMatcher
+ ? `src/**/${fileMatcher}`
+ : "Gulpfile.ts 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts' --exclude 'src/harness/unittests/services/**/*.ts'";
+ const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
+ console.log("Linting: " + cmd);
+ child_process.execSync(cmd, { stdio: [0, 1, 2] });
});
-
gulp.task("default", "Runs 'local'", ["local"]);
gulp.task("watch", "Watches the src/ directory for changes and executes runtests-parallel.", [], () => {
diff --git a/Jakefile.js b/Jakefile.js
index 4512aa23794..9c2b3d38d10 100644
--- a/Jakefile.js
+++ b/Jakefile.js
@@ -11,11 +11,7 @@ var ts = require("./lib/typescript");
// Variables
var compilerDirectory = "src/compiler/";
-var servicesDirectory = "src/services/";
var serverDirectory = "src/server/";
-var typingsInstallerDirectory = "src/server/typingsInstaller";
-var cancellationTokenDirectory = "src/server/cancellationToken";
-var watchGuardDirectory = "src/server/watchGuard";
var harnessDirectory = "src/harness/";
var libraryDirectory = "src/lib/";
var scriptsDirectory = "scripts/";
@@ -131,6 +127,7 @@ var harnessSources = harnessCoreSources.concat([
"matchFiles.ts",
"initializeTSConfig.ts",
"printer.ts",
+ "textChanges.ts",
"transform.ts",
"customTransforms.ts",
].map(function (f) {
@@ -333,7 +330,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
options += " --lib " + opts.lib
}
else {
- options += " --lib es5,scripthost"
+ options += " --lib es5"
}
options += " --noUnusedLocals --noUnusedParameters";
@@ -422,7 +419,7 @@ compileFile(buildProtocolJs,
[buildProtocolTs],
[],
/*useBuiltCompiler*/ false,
- {noOutFile: true});
+ { noOutFile: true, lib: "es6" });
file(buildProtocolDts, [buildProtocolTs, buildProtocolJs, typescriptServicesDts], function() {
@@ -584,16 +581,16 @@ compileFile(
file(typescriptServicesDts, [servicesFile]);
var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js");
-compileFile(cancellationTokenFile, cancellationTokenSources, [builtLocalDirectory].concat(cancellationTokenSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: true });
+compileFile(cancellationTokenFile, cancellationTokenSources, [builtLocalDirectory].concat(cancellationTokenSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: true, lib: "es6" });
var typingsInstallerFile = path.join(builtLocalDirectory, "typingsInstaller.js");
-compileFile(typingsInstallerFile, typingsInstallerSources, [builtLocalDirectory].concat(typingsInstallerSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: false });
+compileFile(typingsInstallerFile, typingsInstallerSources, [builtLocalDirectory].concat(typingsInstallerSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: false, lib: "es6" });
var watchGuardFile = path.join(builtLocalDirectory, "watchGuard.js");
-compileFile(watchGuardFile, watchGuardSources, [builtLocalDirectory].concat(watchGuardSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: false });
+compileFile(watchGuardFile, watchGuardSources, [builtLocalDirectory].concat(watchGuardSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: false, lib: "es6" });
var serverFile = path.join(builtLocalDirectory, "tsserver.js");
-compileFile(serverFile, serverSources, [builtLocalDirectory, copyright, cancellationTokenFile, typingsInstallerFile, watchGuardFile].concat(serverSources).concat(servicesSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], preserveConstEnums: true });
+compileFile(serverFile, serverSources, [builtLocalDirectory, copyright, cancellationTokenFile, typingsInstallerFile, watchGuardFile].concat(serverSources).concat(servicesSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], preserveConstEnums: true, lib: "es6" });
var tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
var tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");
compileFile(
@@ -717,7 +714,7 @@ compileFile(
/*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
/*prefixes*/[],
/*useBuiltCompiler:*/ true,
- /*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"] });
+ /*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"], lib: "es6" });
var internalTests = "internal/";
@@ -1104,7 +1101,8 @@ var tslintRules = [
"noInOperatorRule",
"noIncrementDecrementRule",
"objectLiteralSurroundingSpaceRule",
- "noTypeAssertionWhitespaceRule"
+ "noTypeAssertionWhitespaceRule",
+ "noBomRule"
];
var tslintRulesFiles = tslintRules.map(function (p) {
return path.join(tslintRuleDir, p + ".ts");
@@ -1179,43 +1177,16 @@ function spawnLintWorker(files, callback) {
}
desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex");
-task("lint", ["build-rules"], function () {
+task("lint", ["build-rules"], () => {
if (fold.isTravis()) console.log(fold.start("lint"));
- var startTime = mark();
- var failed = 0;
- var fileMatcher = RegExp(process.env.f || process.env.file || process.env.files || "");
- var done = {};
- for (var i in lintTargets) {
- var target = lintTargets[i];
- if (!done[target] && fileMatcher.test(target)) {
- done[target] = fs.statSync(target).size;
- }
- }
-
- var workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length;
-
- var names = Object.keys(done).sort(function (namea, nameb) {
- return done[namea] - done[nameb];
+ const fileMatcher = process.env.f || process.env.file || process.env.files;
+ const files = fileMatcher
+ ? `src/**/${fileMatcher}`
+ : "Gulpfile.ts 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts' --exclude 'src/harness/unittests/services/**/*.ts'";
+ const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
+ console.log("Linting: " + cmd);
+ jake.exec([cmd], { interactive: true }, () => {
+ if (fold.isTravis()) console.log(fold.end("lint"));
+ complete();
});
-
- for (var i = 0; i < workerCount; i++) {
- spawnLintWorker(names, finished);
- }
-
- var completed = 0;
- var failures = 0;
- function finished(fails) {
- completed++;
- failures += fails;
- if (completed === workerCount) {
- measure(startTime);
- if (fold.isTravis()) console.log(fold.end("lint"));
- if (failures > 0) {
- fail('Linter errors.', failed);
- }
- else {
- complete();
- }
- }
- }
-}, { async: true });
+});
diff --git a/README.md b/README.md
index 2f631439eb0..d21e558360c 100644
--- a/README.md
+++ b/README.md
@@ -39,8 +39,8 @@ with any additional questions or comments.
## Documentation
-* [Quick tutorial](http://www.typescriptlang.org/Tutorial)
-* [Programming handbook](http://www.typescriptlang.org/Handbook)
+* [Quick tutorial](http://www.typescriptlang.org/docs/tutorial.html)
+* [Programming handbook](http://www.typescriptlang.org/docs/handbook/basic-types.html)
* [Language specification](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md)
* [Homepage](http://www.typescriptlang.org/)
@@ -95,4 +95,4 @@ node built/local/tsc.js hello.ts
## Roadmap
-For details on our planned features and future direction please refer to our [roadmap](https://github.com/Microsoft/TypeScript/wiki/Roadmap).
\ No newline at end of file
+For details on our planned features and future direction please refer to our [roadmap](https://github.com/Microsoft/TypeScript/wiki/Roadmap).
diff --git a/doc/logo.svg b/doc/logo.svg
index fc7e0fadd66..2c0dd017a1b 100644
--- a/doc/logo.svg
+++ b/doc/logo.svg
@@ -1,15 +1,10 @@
-
-
+
\ No newline at end of file
diff --git a/issue_template.md b/issue_template.md
index 4d397a0afd6..29190e79763 100644
--- a/issue_template.md
+++ b/issue_template.md
@@ -2,7 +2,7 @@
-**TypeScript Version:** 2.1.1 / nightly (2.2.0-dev.201xxxxx)
+**TypeScript Version:** 2.2.1 / nightly (2.2.0-dev.201xxxxx)
**Code**
diff --git a/scripts/tslint/booleanTriviaRule.ts b/scripts/tslint/booleanTriviaRule.ts
index db6abcbf17b..e79275c6392 100644
--- a/scripts/tslint/booleanTriviaRule.ts
+++ b/scripts/tslint/booleanTriviaRule.ts
@@ -2,52 +2,62 @@ import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
- public static FAILURE_STRING_FACTORY = (name: string, currently: string) => `Tag boolean argument as '${name}' (currently '${currently}')`;
+ public static FAILURE_STRING_FACTORY(name: string, currently?: string): string {
+ const current = currently ? ` (currently '${currently}')` : "";
+ return `Tag boolean argument as '${name}'${current}`;
+ }
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
+ // Cheat to get type checker
const program = ts.createProgram([sourceFile.fileName], Lint.createCompilerOptions());
const checker = program.getTypeChecker();
- return this.applyWithWalker(new BooleanTriviaWalker(checker, program.getSourceFile(sourceFile.fileName), this.getOptions()));
+ return this.applyWithFunction(program.getSourceFile(sourceFile.fileName), ctx => walk(ctx, checker));
}
}
-class BooleanTriviaWalker extends Lint.RuleWalker {
- constructor(private checker: ts.TypeChecker, file: ts.SourceFile, opts: Lint.IOptions) {
- super(file, opts);
+function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void {
+ ts.forEachChild(ctx.sourceFile, recur);
+ function recur(node: ts.Node): void {
+ if (node.kind === ts.SyntaxKind.CallExpression) {
+ checkCall(node as ts.CallExpression);
+ }
+ ts.forEachChild(node, recur);
}
- visitCallExpression(node: ts.CallExpression) {
- super.visitCallExpression(node);
- if (node.arguments && node.arguments.some(arg => arg.kind === ts.SyntaxKind.TrueKeyword || arg.kind === ts.SyntaxKind.FalseKeyword)) {
- const targetCallSignature = this.checker.getResolvedSignature(node);
- if (!!targetCallSignature) {
- const targetParameters = targetCallSignature.getParameters();
- const source = this.getSourceFile();
- for (let index = 0; index < targetParameters.length; index++) {
- const param = targetParameters[index];
- const arg = node.arguments[index];
- if (!(arg && param)) {
- continue;
- }
+ function checkCall(node: ts.CallExpression): void {
+ if (!node.arguments || !node.arguments.some(arg => arg.kind === ts.SyntaxKind.TrueKeyword || arg.kind === ts.SyntaxKind.FalseKeyword)) {
+ return;
+ }
- const argType = this.checker.getContextualType(arg);
- if (argType && (argType.getFlags() & ts.TypeFlags.Boolean)) {
- if (arg.kind !== ts.SyntaxKind.TrueKeyword && arg.kind !== ts.SyntaxKind.FalseKeyword) {
- continue;
- }
- let triviaContent: string;
- const ranges = ts.getLeadingCommentRanges(arg.getFullText(), 0);
- if (ranges && ranges.length === 1 && ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) {
- triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); // +/-2 to remove /**/
- }
+ const targetCallSignature = checker.getResolvedSignature(node);
+ if (!targetCallSignature) {
+ return;
+ }
- const paramName = param.getName();
- if (triviaContent !== paramName && triviaContent !== paramName + ":") {
- this.addFailure(this.createFailure(arg.getStart(source), arg.getWidth(source), Rule.FAILURE_STRING_FACTORY(param.getName(), triviaContent)));
- }
- }
+ const targetParameters = targetCallSignature.getParameters();
+ for (let index = 0; index < targetParameters.length; index++) {
+ const param = targetParameters[index];
+ const arg = node.arguments[index];
+ if (!(arg && param)) {
+ continue;
+ }
+
+ const argType = checker.getContextualType(arg);
+ if (argType && (argType.getFlags() & ts.TypeFlags.Boolean)) {
+ if (arg.kind !== ts.SyntaxKind.TrueKeyword && arg.kind !== ts.SyntaxKind.FalseKeyword) {
+ continue;
+ }
+ let triviaContent: string | undefined;
+ const ranges = ts.getLeadingCommentRanges(arg.getFullText(), 0);
+ if (ranges && ranges.length === 1 && ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) {
+ triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); // +/-2 to remove /**/
+ }
+
+ const paramName = param.getName();
+ if (triviaContent !== paramName && triviaContent !== paramName + ":") {
+ ctx.addFailureAtNode(arg, Rule.FAILURE_STRING_FACTORY(param.getName(), triviaContent));
}
}
}
}
-}
+}
\ No newline at end of file
diff --git a/scripts/tslint/nextLineRule.ts b/scripts/tslint/nextLineRule.ts
index 2dee393bd84..b149d09eb38 100644
--- a/scripts/tslint/nextLineRule.ts
+++ b/scripts/tslint/nextLineRule.ts
@@ -9,50 +9,56 @@ export class Rule extends Lint.Rules.AbstractRule {
public static ELSE_FAILURE_STRING = "'else' should not be on the same line as the preceeding block's curly brace";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
- return this.applyWithWalker(new NextLineWalker(sourceFile, this.getOptions()));
+ const options = this.getOptions().ruleArguments;
+ const checkCatch = options.indexOf(OPTION_CATCH) !== -1;
+ const checkElse = options.indexOf(OPTION_ELSE) !== -1;
+ return this.applyWithFunction(sourceFile, ctx => walk(ctx, checkCatch, checkElse));
}
}
-class NextLineWalker extends Lint.RuleWalker {
- public visitIfStatement(node: ts.IfStatement) {
- const sourceFile = node.getSourceFile();
- const thenStatement = node.thenStatement;
-
- const elseStatement = node.elseStatement;
- if (!!elseStatement) {
- // find the else keyword
- const elseKeyword = getFirstChildOfKind(node, ts.SyntaxKind.ElseKeyword);
- if (this.hasOption(OPTION_ELSE) && !!elseKeyword) {
- const thenStatementEndLoc = sourceFile.getLineAndCharacterOfPosition(thenStatement.getEnd());
- const elseKeywordLoc = sourceFile.getLineAndCharacterOfPosition(elseKeyword.getStart(sourceFile));
- if (thenStatementEndLoc.line === elseKeywordLoc.line) {
- const failure = this.createFailure(elseKeyword.getStart(sourceFile), elseKeyword.getWidth(sourceFile), Rule.ELSE_FAILURE_STRING);
- this.addFailure(failure);
- }
- }
+function walk(ctx: Lint.WalkContext, checkCatch: boolean, checkElse: boolean): void {
+ const { sourceFile } = ctx;
+ function recur(node: ts.Node): void {
+ switch (node.kind) {
+ case ts.SyntaxKind.IfStatement:
+ checkIf(node as ts.IfStatement);
+ break;
+ case ts.SyntaxKind.TryStatement:
+ checkTry(node as ts.TryStatement);
+ break;
}
-
- super.visitIfStatement(node);
+ ts.forEachChild(node, recur);
}
- public visitTryStatement(node: ts.TryStatement) {
- const sourceFile = node.getSourceFile();
- const catchClause = node.catchClause;
+ function checkIf(node: ts.IfStatement): void {
+ const { thenStatement, elseStatement } = node;
+ if (!elseStatement) {
+ return;
+ }
- // "visit" try block
- const tryBlock = node.tryBlock;
-
- if (this.hasOption(OPTION_CATCH) && !!catchClause) {
- const tryClosingBrace = tryBlock.getLastToken(sourceFile);
- const catchKeyword = catchClause.getFirstToken(sourceFile);
- const tryClosingBraceLoc = sourceFile.getLineAndCharacterOfPosition(tryClosingBrace.getEnd());
- const catchKeywordLoc = sourceFile.getLineAndCharacterOfPosition(catchKeyword.getStart(sourceFile));
- if (tryClosingBraceLoc.line === catchKeywordLoc.line) {
- const failure = this.createFailure(catchKeyword.getStart(sourceFile), catchKeyword.getWidth(sourceFile), Rule.CATCH_FAILURE_STRING);
- this.addFailure(failure);
+ // find the else keyword
+ const elseKeyword = getFirstChildOfKind(node, ts.SyntaxKind.ElseKeyword);
+ if (checkElse && !!elseKeyword) {
+ const thenStatementEndLoc = sourceFile.getLineAndCharacterOfPosition(thenStatement.getEnd());
+ const elseKeywordLoc = sourceFile.getLineAndCharacterOfPosition(elseKeyword.getStart(sourceFile));
+ if (thenStatementEndLoc.line === elseKeywordLoc.line) {
+ ctx.addFailureAtNode(elseKeyword, Rule.ELSE_FAILURE_STRING);
}
}
- super.visitTryStatement(node);
+ }
+
+ function checkTry({ tryBlock, catchClause }: ts.TryStatement): void {
+ if (!checkCatch || !catchClause) {
+ return;
+ }
+
+ const tryClosingBrace = tryBlock.getLastToken(sourceFile);
+ const catchKeyword = catchClause.getFirstToken(sourceFile);
+ const tryClosingBraceLoc = sourceFile.getLineAndCharacterOfPosition(tryClosingBrace.getEnd());
+ const catchKeywordLoc = sourceFile.getLineAndCharacterOfPosition(catchKeyword.getStart(sourceFile));
+ if (tryClosingBraceLoc.line === catchKeywordLoc.line) {
+ ctx.addFailureAtNode(catchKeyword, Rule.CATCH_FAILURE_STRING);
+ }
}
}
diff --git a/scripts/tslint/noBomRule.ts b/scripts/tslint/noBomRule.ts
new file mode 100644
index 00000000000..105e2d2d68c
--- /dev/null
+++ b/scripts/tslint/noBomRule.ts
@@ -0,0 +1,16 @@
+import * as Lint from "tslint/lib";
+import * as ts from "typescript";
+
+export class Rule extends Lint.Rules.AbstractRule {
+ public static FAILURE_STRING = "This file has a BOM.";
+
+ public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
+ return this.applyWithFunction(sourceFile, walk);
+ }
+}
+
+function walk(ctx: Lint.WalkContext): void {
+ if (ctx.sourceFile.text[0] === "\ufeff") {
+ ctx.addFailure(0, 1, Rule.FAILURE_STRING);
+ }
+}
diff --git a/scripts/tslint/noInOperatorRule.ts b/scripts/tslint/noInOperatorRule.ts
index 307f0dffd6a..95f052ccaa6 100644
--- a/scripts/tslint/noInOperatorRule.ts
+++ b/scripts/tslint/noInOperatorRule.ts
@@ -1,20 +1,19 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
-
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "Don't use the 'in' keyword - use 'hasProperty' to check for key presence instead";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
- return this.applyWithWalker(new InWalker(sourceFile, this.getOptions()));
+ return this.applyWithFunction(sourceFile, walk);
}
}
-class InWalker extends Lint.RuleWalker {
- visitNode(node: ts.Node) {
- super.visitNode(node);
- if (node.kind === ts.SyntaxKind.InKeyword && node.parent && node.parent.kind === ts.SyntaxKind.BinaryExpression) {
- this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
+function walk(ctx: Lint.WalkContext): void {
+ ts.forEachChild(ctx.sourceFile, recur);
+ function recur(node: ts.Node): void {
+ if (node.kind === ts.SyntaxKind.InKeyword && node.parent.kind === ts.SyntaxKind.BinaryExpression) {
+ ctx.addFailureAtNode(node, Rule.FAILURE_STRING);
}
}
}
diff --git a/scripts/tslint/noIncrementDecrementRule.ts b/scripts/tslint/noIncrementDecrementRule.ts
index 2a957b36af5..ff2d81b1962 100644
--- a/scripts/tslint/noIncrementDecrementRule.ts
+++ b/scripts/tslint/noIncrementDecrementRule.ts
@@ -1,44 +1,55 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
-
export class Rule extends Lint.Rules.AbstractRule {
public static POSTFIX_FAILURE_STRING = "Don't use '++' or '--' postfix operators outside statements or for loops.";
public static PREFIX_FAILURE_STRING = "Don't use '++' or '--' prefix operators.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
- return this.applyWithWalker(new IncrementDecrementWalker(sourceFile, this.getOptions()));
+ return this.applyWithFunction(sourceFile, walk);
}
}
-class IncrementDecrementWalker extends Lint.RuleWalker {
+function walk(ctx: Lint.WalkContext): void {
+ ts.forEachChild(ctx.sourceFile, recur);
+ function recur(node: ts.Node): void {
+ switch (node.kind) {
+ case ts.SyntaxKind.PrefixUnaryExpression:
+ const { operator } = node as ts.PrefixUnaryExpression;
+ if (operator === ts.SyntaxKind.PlusPlusToken || operator === ts.SyntaxKind.MinusMinusToken) {
+ check(node as ts.PrefixUnaryExpression);
+ }
+ break;
- visitPostfixUnaryExpression(node: ts.PostfixUnaryExpression) {
- super.visitPostfixUnaryExpression(node);
- if (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator == ts.SyntaxKind.MinusMinusToken) {
- this.visitIncrementDecrement(node);
+ case ts.SyntaxKind.PostfixUnaryExpression:
+ check(node as ts.PostfixUnaryExpression);
+ break;
}
}
- visitPrefixUnaryExpression(node: ts.PrefixUnaryExpression) {
- super.visitPrefixUnaryExpression(node);
- if (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator == ts.SyntaxKind.MinusMinusToken) {
- this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.PREFIX_FAILURE_STRING));
+ function check(node: ts.UnaryExpression): void {
+ if (!isAllowedLocation(node.parent!)) {
+ ctx.addFailureAtNode(node, Rule.POSTFIX_FAILURE_STRING);
}
}
+}
- visitIncrementDecrement(node: ts.UnaryExpression) {
- if (node.parent && (
- // Can be a statement
- node.parent.kind === ts.SyntaxKind.ExpressionStatement ||
- // Can be directly in a for-statement
- node.parent.kind === ts.SyntaxKind.ForStatement ||
- // Can be in a comma operator in a for statement (`for (let a = 0, b = 10; a < b; a++, b--)`)
- node.parent.kind === ts.SyntaxKind.BinaryExpression &&
- (node.parent).operatorToken.kind === ts.SyntaxKind.CommaToken &&
- node.parent.parent.kind === ts.SyntaxKind.ForStatement)) {
- return;
- }
- this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.POSTFIX_FAILURE_STRING));
+function isAllowedLocation(node: ts.Node): boolean {
+ switch (node.kind) {
+ // Can be a statement
+ case ts.SyntaxKind.ExpressionStatement:
+ return true;
+
+ // Can be directly in a for-statement
+ case ts.SyntaxKind.ForStatement:
+ return true;
+
+ // Can be in a comma operator in a for statement (`for (let a = 0, b = 10; a < b; a++, b--)`)
+ case ts.SyntaxKind.BinaryExpression:
+ return (node as ts.BinaryExpression).operatorToken.kind === ts.SyntaxKind.CommaToken &&
+ node.parent!.kind === ts.SyntaxKind.ForStatement;
+
+ default:
+ return false;
}
}
diff --git a/scripts/tslint/noTypeAssertionWhitespaceRule.ts b/scripts/tslint/noTypeAssertionWhitespaceRule.ts
index 5368dcf74ba..37017fb60e4 100644
--- a/scripts/tslint/noTypeAssertionWhitespaceRule.ts
+++ b/scripts/tslint/noTypeAssertionWhitespaceRule.ts
@@ -1,25 +1,25 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
-
export class Rule extends Lint.Rules.AbstractRule {
public static TRAILING_FAILURE_STRING = "Excess trailing whitespace found around type assertion.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
- return this.applyWithWalker(new TypeAssertionWhitespaceWalker(sourceFile, this.getOptions()));
+ return this.applyWithFunction(sourceFile, walk);
}
}
-class TypeAssertionWhitespaceWalker extends Lint.RuleWalker {
- public visitNode(node: ts.Node) {
+function walk(ctx: Lint.WalkContext): void {
+ ts.forEachChild(ctx.sourceFile, recur);
+ function recur(node: ts.Node) {
if (node.kind === ts.SyntaxKind.TypeAssertionExpression) {
const refined = node as ts.TypeAssertion;
const leftSideWhitespaceStart = refined.type.getEnd() + 1;
const rightSideWhitespaceEnd = refined.expression.getStart();
if (leftSideWhitespaceStart !== rightSideWhitespaceEnd) {
- this.addFailure(this.createFailure(leftSideWhitespaceStart, rightSideWhitespaceEnd, Rule.TRAILING_FAILURE_STRING));
+ ctx.addFailure(leftSideWhitespaceStart, rightSideWhitespaceEnd, Rule.TRAILING_FAILURE_STRING);
}
}
- super.visitNode(node);
+ ts.forEachChild(node, recur);
}
}
diff --git a/scripts/tslint/objectLiteralSurroundingSpaceRule.ts b/scripts/tslint/objectLiteralSurroundingSpaceRule.ts
index a705e56c969..8546aa6c973 100644
--- a/scripts/tslint/objectLiteralSurroundingSpaceRule.ts
+++ b/scripts/tslint/objectLiteralSurroundingSpaceRule.ts
@@ -1,7 +1,6 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
-
export class Rule extends Lint.Rules.AbstractRule {
public static LEADING_FAILURE_STRING = "No leading whitespace found on single-line object literal.";
public static TRAILING_FAILURE_STRING = "No trailing whitespace found on single-line object literal.";
@@ -9,34 +8,37 @@ export class Rule extends Lint.Rules.AbstractRule {
public static TRAILING_EXCESS_FAILURE_STRING = "Excess trailing whitespace found on single-line object literal.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
- return this.applyWithWalker(new ObjectLiteralSpaceWalker(sourceFile, this.getOptions()));
+ return this.applyWithFunction(sourceFile, walk);
}
}
-class ObjectLiteralSpaceWalker extends Lint.RuleWalker {
- public visitNode(node: ts.Node) {
+function walk(ctx: Lint.WalkContext): void {
+ const { sourceFile } = ctx;
+ ts.forEachChild(sourceFile, recur);
+ function recur(node: ts.Node): void {
if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) {
- const literal = node as ts.ObjectLiteralExpression;
- const text = literal.getText();
- if (text.match(/^{[^\n]+}$/g)) {
- if (text.charAt(1) !== " ") {
- const failure = this.createFailure(node.pos, node.getWidth(), Rule.LEADING_FAILURE_STRING);
- this.addFailure(failure);
- }
- if (text.charAt(2) === " ") {
- const failure = this.createFailure(node.pos + 2, 1, Rule.LEADING_EXCESS_FAILURE_STRING);
- this.addFailure(failure);
- }
- if (text.charAt(text.length - 2) !== " ") {
- const failure = this.createFailure(node.pos, node.getWidth(), Rule.TRAILING_FAILURE_STRING);
- this.addFailure(failure);
- }
- if (text.charAt(text.length - 3) === " ") {
- const failure = this.createFailure(node.pos + node.getWidth() - 3, 1, Rule.TRAILING_EXCESS_FAILURE_STRING);
- this.addFailure(failure);
- }
- }
+ check(node as ts.ObjectLiteralExpression);
+ }
+ ts.forEachChild(node, recur);
+ }
+
+ function check(node: ts.ObjectLiteralExpression): void {
+ const text = node.getText(sourceFile);
+ if (!text.match(/^{[^\n]+}$/g)) {
+ return;
+ }
+
+ if (text.charAt(1) !== " ") {
+ ctx.addFailureAtNode(node, Rule.LEADING_FAILURE_STRING);
+ }
+ if (text.charAt(2) === " ") {
+ ctx.addFailureAt(node.pos + 2, 1, Rule.LEADING_EXCESS_FAILURE_STRING);
+ }
+ if (text.charAt(text.length - 2) !== " ") {
+ ctx.addFailureAtNode(node, Rule.TRAILING_FAILURE_STRING);
+ }
+ if (text.charAt(text.length - 3) === " ") {
+ ctx.addFailureAt(node.pos + node.getWidth() - 3, 1, Rule.TRAILING_EXCESS_FAILURE_STRING);
}
- super.visitNode(node);
}
}
diff --git a/scripts/tslint/tsconfig.json b/scripts/tslint/tsconfig.json
index db018ce2776..c9bf8dc01dc 100644
--- a/scripts/tslint/tsconfig.json
+++ b/scripts/tslint/tsconfig.json
@@ -1,6 +1,11 @@
{
"compilerOptions": {
"noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "strictNullChecks": true,
"module": "commonjs",
"outDir": "../../built/local/tslint"
}
diff --git a/scripts/tslint/typeOperatorSpacingRule.ts b/scripts/tslint/typeOperatorSpacingRule.ts
index 50f2971a0ee..4bd70e6eefa 100644
--- a/scripts/tslint/typeOperatorSpacingRule.ts
+++ b/scripts/tslint/typeOperatorSpacingRule.ts
@@ -1,34 +1,36 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
-
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "The '|' and '&' operators must be surrounded by single spaces";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
- return this.applyWithWalker(new TypeOperatorSpacingWalker(sourceFile, this.getOptions()));
+ return this.applyWithFunction(sourceFile, walk);
}
}
-class TypeOperatorSpacingWalker extends Lint.RuleWalker {
- public visitNode(node: ts.Node) {
+function walk(ctx: Lint.WalkContext): void {
+ const { sourceFile } = ctx;
+ ts.forEachChild(sourceFile, recur);
+ function recur(node: ts.Node): void {
if (node.kind === ts.SyntaxKind.UnionType || node.kind === ts.SyntaxKind.IntersectionType) {
- const types = (node).types;
- let expectedStart = types[0].end + 2; // space, | or &
- for (let i = 1; i < types.length; i++) {
- const currentType = types[i];
- if (expectedStart !== currentType.pos || currentType.getLeadingTriviaWidth() !== 1) {
- const sourceFile = currentType.getSourceFile();
- const previousTypeEndPos = sourceFile.getLineAndCharacterOfPosition(types[i - 1].end);
- const currentTypeStartPos = sourceFile.getLineAndCharacterOfPosition(currentType.pos);
- if (previousTypeEndPos.line === currentTypeStartPos.line) {
- const failure = this.createFailure(currentType.pos, currentType.getWidth(), Rule.FAILURE_STRING);
- this.addFailure(failure);
- }
+ check((node as ts.UnionOrIntersectionTypeNode).types);
+ }
+ ts.forEachChild(node, recur);
+ }
+
+ function check(types: ts.TypeNode[]): void {
+ let expectedStart = types[0].end + 2; // space, | or &
+ for (let i = 1; i < types.length; i++) {
+ const currentType = types[i];
+ if (expectedStart !== currentType.pos || currentType.getLeadingTriviaWidth() !== 1) {
+ const previousTypeEndPos = sourceFile.getLineAndCharacterOfPosition(types[i - 1].end);
+ const currentTypeStartPos = sourceFile.getLineAndCharacterOfPosition(currentType.pos);
+ if (previousTypeEndPos.line === currentTypeStartPos.line) {
+ ctx.addFailureAtNode(currentType, Rule.FAILURE_STRING);
}
- expectedStart = currentType.end + 2;
}
+ expectedStart = currentType.end + 2;
}
- super.visitNode(node);
}
}
diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index 7e8a99343bd..650797c6dba 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -182,7 +182,7 @@ namespace ts {
return bindSourceFile;
function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean {
- if (opts.alwaysStrict && !isDeclarationFile(file)) {
+ if ((opts.alwaysStrict === undefined ? opts.strict : opts.alwaysStrict) && !isDeclarationFile(file)) {
// bind in strict mode source files with alwaysStrict option
return true;
}
@@ -1903,7 +1903,7 @@ namespace ts {
// Even though in the AST the jsdoc @typedef node belongs to the current node,
// its symbol might be in the same scope with the current node's symbol. Consider:
- //
+ //
// /** @typedef {string | number} MyType */
// function foo();
//
@@ -2289,7 +2289,42 @@ namespace ts {
declareSymbol(file.symbol.exports, file.symbol, node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
}
+ function isExportsOrModuleExportsOrAlias(node: Node): boolean {
+ return isExportsIdentifier(node) ||
+ isModuleExportsPropertyAccessExpression(node) ||
+ isNameOfExportsOrModuleExportsAliasDeclaration(node);
+ }
+
+ function isNameOfExportsOrModuleExportsAliasDeclaration(node: Node) {
+ if (node.kind === SyntaxKind.Identifier) {
+ const symbol = container.locals.get((node).text);
+ if (symbol && symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
+ const declaration = symbol.valueDeclaration as VariableDeclaration;
+ if (declaration.initializer) {
+ return isExportsOrModuleExportsOrAliasOrAssignemnt(declaration.initializer);
+ }
+ }
+ }
+ return false;
+ }
+
+ function isExportsOrModuleExportsOrAliasOrAssignemnt(node: Node): boolean {
+ return isExportsOrModuleExportsOrAlias(node) ||
+ (isAssignmentExpression(node, /*excludeCompoundAssignements*/ true) && (isExportsOrModuleExportsOrAliasOrAssignemnt(node.left) || isExportsOrModuleExportsOrAliasOrAssignemnt(node.right)));
+ }
+
function bindModuleExportsAssignment(node: BinaryExpression) {
+ // A common practice in node modules is to set 'export = module.exports = {}', this ensures that 'exports'
+ // is still pointing to 'module.exports'.
+ // We do not want to consider this as 'export=' since a module can have only one of these.
+ // Similarlly we do not want to treat 'module.exports = exports' as an 'export='.
+ const assignedExpression = getRightMostAssignedExpression(node.right);
+ if (isEmptyObjectLiteral(assignedExpression) || isExportsOrModuleExportsOrAlias(assignedExpression)) {
+ // Mark it as a module in case there are no other exports in the file
+ setCommonJsModuleIndicator(node);
+ return;
+ }
+
// 'module.exports = expr' assignment
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
@@ -2297,23 +2332,30 @@ namespace ts {
function bindThisPropertyAssignment(node: BinaryExpression) {
Debug.assert(isInJavaScriptFile(node));
- // Declare a 'member' if the container is an ES5 class or ES6 constructor
- if (container.kind === SyntaxKind.FunctionDeclaration || container.kind === SyntaxKind.FunctionExpression) {
- container.symbol.members = container.symbol.members || createMap();
- // It's acceptable for multiple 'this' assignments of the same identifier to occur
- declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
- }
- else if (container.kind === SyntaxKind.Constructor) {
- // this.foo assignment in a JavaScript class
- // Bind this property to the containing class
- const saveContainer = container;
- container = container.parent;
- const symbol = bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.None);
- if (symbol) {
- // constructor-declared symbols can be overwritten by subsequent method declarations
- (symbol as Symbol).isReplaceableByMethod = true;
- }
- container = saveContainer;
+ const container = getThisContainer(node, /*includeArrowFunctions*/false);
+ switch (container.kind) {
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.FunctionExpression:
+ // Declare a 'member' if the container is an ES5 class or ES6 constructor
+ container.symbol.members = container.symbol.members || createMap();
+ // It's acceptable for multiple 'this' assignments of the same identifier to occur
+ declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
+ break;
+
+ case SyntaxKind.Constructor:
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ // this.foo assignment in a JavaScript class
+ // Bind this property to the containing class
+ const containingClass = container.parent;
+ const symbol = declareSymbol(hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None);
+ if (symbol) {
+ // symbols declared through 'this' property assignements can be overwritten by subsequent method declarations
+ (symbol as Symbol).isReplaceableByMethod = true;
+ }
+ break;
}
}
@@ -2346,11 +2388,20 @@ namespace ts {
leftSideOfAssignment.parent = node;
target.parent = leftSideOfAssignment;
- bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false);
+ if (isNameOfExportsOrModuleExportsAliasDeclaration(target)) {
+ // This can be an alias for the 'exports' or 'module.exports' names, e.g.
+ // var util = module.exports;
+ // util.property = function ...
+ bindExportsPropertyAssignment(node);
+ }
+ else {
+ bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false);
+ }
}
function bindPropertyAssignment(functionName: string, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
let targetSymbol = container.locals.get(functionName);
+
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) {
targetSymbol = (targetSymbol.valueDeclaration as VariableDeclaration).initializer.symbol;
}
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index a4c0acc405d..b581ca315b4 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -1,4 +1,4 @@
-///
+///
///
/* @internal */
@@ -56,7 +56,9 @@ namespace ts {
const modulekind = getEmitModuleKind(compilerOptions);
const noUnusedIdentifiers = !!compilerOptions.noUnusedLocals || !!compilerOptions.noUnusedParameters;
const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System;
- const strictNullChecks = compilerOptions.strictNullChecks;
+ const strictNullChecks = compilerOptions.strictNullChecks === undefined ? compilerOptions.strict : compilerOptions.strictNullChecks;
+ const noImplicitAny = compilerOptions.noImplicitAny === undefined ? compilerOptions.strict : compilerOptions.noImplicitAny;
+ const noImplicitThis = compilerOptions.noImplicitThis === undefined ? compilerOptions.strict : compilerOptions.noImplicitThis;
const emitResolver = createResolver();
@@ -242,6 +244,7 @@ namespace ts {
const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
+ const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
const globals = createMap();
/**
@@ -259,6 +262,7 @@ namespace ts {
let globalNumberType: ObjectType;
let globalBooleanType: ObjectType;
let globalRegExpType: ObjectType;
+ let globalThisType: GenericType;
let anyArrayType: Type;
let autoArrayType: Type;
let anyReadonlyArrayType: Type;
@@ -434,6 +438,12 @@ namespace ts {
ResolvedReturnType
}
+ const enum CheckMode {
+ Normal = 0, // Normal type checking
+ SkipContextSensitive = 1, // Skip context sensitive function expressions
+ Inferential = 2, // Inferential typing
+ }
+
const builtinGlobals = createMap();
builtinGlobals.set(undefinedSymbol.name, undefinedSymbol);
@@ -1564,7 +1574,7 @@ namespace ts {
error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName);
return undefined;
}
- else if (compilerOptions.noImplicitAny && moduleNotFoundError) {
+ else if (noImplicitAny && moduleNotFoundError) {
error(errorNode,
Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type,
moduleReference,
@@ -3359,16 +3369,6 @@ namespace ts {
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
}
- /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
- function removeOptionalityFromAnnotation(annotatedType: Type, declaration: VariableLikeDeclaration): Type {
- const annotationIncludesUndefined = strictNullChecks &&
- declaration.kind === SyntaxKind.Parameter &&
- declaration.initializer &&
- getFalsyFlags(annotatedType) & TypeFlags.Undefined &&
- !(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
- return annotationIncludesUndefined ? getNonNullableType(annotatedType) : annotatedType;
- }
-
// Return the inferred type for a variable, parameter, or property declaration
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
if (declaration.flags & NodeFlags.JavaScriptFile) {
@@ -3403,11 +3403,11 @@ namespace ts {
// Use type from type annotation if one is present
if (declaration.type) {
- const declaredType = removeOptionalityFromAnnotation(getTypeFromTypeNode(declaration.type), declaration);
+ const declaredType = getTypeFromTypeNode(declaration.type);
return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
}
- if ((compilerOptions.noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) &&
+ if ((noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) &&
declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) &&
!(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !isInAmbientContext(declaration)) {
// If --noImplicitAny is on or the declaration is in a Javascript file,
@@ -3478,25 +3478,41 @@ namespace ts {
return undefined;
}
- // Return the inferred type for a variable, parameter, or property declaration
- function getTypeForJSSpecialPropertyDeclaration(declaration: Declaration): Type {
- const expression = declaration.kind === SyntaxKind.BinaryExpression ? declaration :
- declaration.kind === SyntaxKind.PropertyAccessExpression ? getAncestor(declaration, SyntaxKind.BinaryExpression) :
- undefined;
+ function getWidenedTypeFromJSSpecialPropertyDeclarations(symbol: Symbol) {
+ const types: Type[] = [];
+ let definedInConstructor = false;
+ let definedInMethod = false;
+ for (const declaration of symbol.declarations) {
+ const expression = declaration.kind === SyntaxKind.BinaryExpression ? declaration :
+ declaration.kind === SyntaxKind.PropertyAccessExpression ? getAncestor(declaration, SyntaxKind.BinaryExpression) :
+ undefined;
- if (!expression) {
- return unknownType;
- }
-
- if (expression.flags & NodeFlags.JavaScriptFile) {
- // If there is a JSDoc type, use it
- const type = getTypeForDeclarationFromJSDocComment(expression.parent);
- if (type && type !== unknownType) {
- return getWidenedType(type);
+ if (!expression) {
+ return unknownType;
}
+
+ if (isPropertyAccessExpression(expression.left) && expression.left.expression.kind === SyntaxKind.ThisKeyword) {
+ if (getThisContainer(expression, /*includeArrowFunctions*/ false).kind === SyntaxKind.Constructor) {
+ definedInConstructor = true;
+ }
+ else {
+ definedInMethod = true;
+ }
+ }
+
+ if (expression.flags & NodeFlags.JavaScriptFile) {
+ // If there is a JSDoc type, use it
+ const type = getTypeForDeclarationFromJSDocComment(expression.parent);
+ if (type && type !== unknownType) {
+ types.push(getWidenedType(type));
+ continue;
+ }
+ }
+
+ types.push(getWidenedLiteralType(checkExpressionCached(expression.right)));
}
- return getWidenedLiteralType(checkExpressionCached(expression.right));
+ return getWidenedType(addOptionality(getUnionType(types, /*subtypeReduction*/ true), definedInMethod && !definedInConstructor));
}
// Return the type implied by a binding pattern element. This is the type of the initializer of the element if
@@ -3509,7 +3525,7 @@ namespace ts {
if (isBindingPattern(element.name)) {
return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors);
}
- if (reportErrors && compilerOptions.noImplicitAny && !declarationBelongsToPrivateAmbientMember(element)) {
+ if (reportErrors && noImplicitAny && !declarationBelongsToPrivateAmbientMember(element)) {
reportImplicitAnyError(element, anyType);
}
return anyType;
@@ -3607,7 +3623,7 @@ namespace ts {
type = declaration.dotDotDotToken ? anyArrayType : anyType;
// Report implicit any errors unless this is a private property within an ambient declaration
- if (reportErrors && compilerOptions.noImplicitAny) {
+ if (reportErrors && noImplicitAny) {
if (!declarationBelongsToPrivateAmbientMember(declaration)) {
reportImplicitAnyError(declaration, type);
}
@@ -3653,7 +3669,7 @@ namespace ts {
// * className.prototype.method = expr
if (declaration.kind === SyntaxKind.BinaryExpression ||
declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) {
- type = getWidenedType(getUnionType(map(symbol.declarations, getTypeForJSSpecialPropertyDeclaration), /*subtypeReduction*/ true));
+ type = getWidenedTypeFromJSSpecialPropertyDeclarations(symbol);
}
else {
type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true);
@@ -3726,7 +3742,7 @@ namespace ts {
}
// Otherwise, fall back to 'any'.
else {
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
if (setter) {
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
}
@@ -3741,7 +3757,7 @@ namespace ts {
}
if (!popTypeResolution()) {
type = anyType;
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
}
@@ -3824,7 +3840,7 @@ namespace ts {
return unknownType;
}
// Otherwise variable has initializer that circularly references the variable itself
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer,
symbolToString(symbol));
}
@@ -3957,7 +3973,7 @@ namespace ts {
return true;
}
if (type.flags & TypeFlags.TypeVariable) {
- const constraint = getBaseConstraintOfType(type);
+ const constraint = getBaseConstraintOfType(type);
return constraint && isValidBaseType(constraint) && isMixinConstructorType(constraint);
}
return false;
@@ -4973,16 +4989,32 @@ namespace ts {
}
function getConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type {
- return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) : getBaseConstraintOfType(type);
+ return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) :
+ type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type) :
+ getBaseConstraintOfType(type);
}
function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type {
return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined;
}
- function getBaseConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type {
- const constraint = getResolvedBaseConstraint(type);
- return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined;
+ function getConstraintOfIndexedAccess(type: IndexedAccessType) {
+ const baseObjectType = getBaseConstraintOfType(type.objectType);
+ const baseIndexType = getBaseConstraintOfType(type.indexType);
+ return baseObjectType || baseIndexType ? getIndexedAccessType(baseObjectType || type.objectType, baseIndexType || type.indexType) : undefined;
+ }
+
+ function getBaseConstraintOfType(type: Type): Type {
+ if (type.flags & (TypeFlags.TypeVariable | TypeFlags.UnionOrIntersection)) {
+ const constraint = getResolvedBaseConstraint(type);
+ if (constraint !== noConstraintType && constraint !== circularConstraintType) {
+ return constraint;
+ }
+ }
+ else if (type.flags & TypeFlags.Index) {
+ return stringType;
+ }
+ return undefined;
}
function hasNonCircularBaseConstraint(type: TypeVariable): boolean {
@@ -5080,7 +5112,7 @@ namespace ts {
* type itself. Note that the apparent type of a union type is the union type itself.
*/
function getApparentType(type: Type): Type {
- const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type;
+ const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type;
return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) :
t.flags & TypeFlags.StringLike ? globalStringType :
t.flags & TypeFlags.NumberLike ? globalNumberType :
@@ -5097,7 +5129,8 @@ namespace ts {
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
// Flags we want to propagate to the result if they exist in all source symbols
let commonFlags = isUnion ? SymbolFlags.None : SymbolFlags.Optional;
- let checkFlags = CheckFlags.SyntheticProperty;
+ let syntheticFlag = CheckFlags.SyntheticMethod;
+ let checkFlags = 0;
for (const current of types) {
const type = getApparentType(current);
if (type !== unknownType) {
@@ -5116,6 +5149,9 @@ namespace ts {
(modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) |
(modifiers & ModifierFlags.Private ? CheckFlags.ContainsPrivate : 0) |
(modifiers & ModifierFlags.Static ? CheckFlags.ContainsStatic : 0);
+ if (!isMethodLike(prop)) {
+ syntheticFlag = CheckFlags.SyntheticProperty;
+ }
}
else if (isUnion) {
checkFlags |= CheckFlags.Partial;
@@ -5145,7 +5181,7 @@ namespace ts {
propTypes.push(type);
}
const result = createSymbol(SymbolFlags.Property | commonFlags, name);
- result.checkFlags = checkFlags;
+ result.checkFlags = syntheticFlag | checkFlags;
result.containingType = containingType;
result.declarations = declarations;
result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes);
@@ -5585,7 +5621,7 @@ namespace ts {
}
if (!popTypeResolution()) {
type = anyType;
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
const declaration = signature.declaration;
if (declaration.name) {
error(declaration.name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(declaration.name));
@@ -6083,6 +6119,11 @@ namespace ts {
return deferredGlobalIterableIteratorType || (deferredGlobalIterableIteratorType = getGlobalType("IterableIterator", /*arity*/ 1, reportErrors)) || emptyGenericType;
}
+ function getGlobalTypeOrUndefined(name: string, arity = 0): ObjectType {
+ const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined);
+ return symbol && getTypeOfGlobalSymbol(symbol, arity);
+ }
+
/**
* Returns a type that is inside a namespace at the global scope, e.g.
* getExportedTypeFromNamespace('JSX', 'Element') returns the JSX.Element type
@@ -6540,7 +6581,7 @@ namespace ts {
return indexInfo.type;
}
if (accessExpression && !isConstEnumObjectType(objectType)) {
- if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) {
+ if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) {
if (getIndexTypeOfType(objectType, IndexKind.Number)) {
error(accessExpression.argumentExpression, Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number);
}
@@ -7900,7 +7941,7 @@ namespace ts {
}
// A type S is related to a type T[K] if S is related to A[K], where K is string-like and
// A is the apparent type of S.
- const constraint = getBaseConstraintOfType(target);
+ const constraint = getBaseConstraintOfType(target);
if (constraint) {
if (result = isRelatedTo(source, constraint, reportErrors)) {
errorInfo = saveErrorInfo;
@@ -7940,7 +7981,7 @@ namespace ts {
else if (source.flags & TypeFlags.IndexedAccess) {
// A type S[K] is related to a type T if A[K] is related to T, where K is string-like and
// A is the apparent type of S.
- const constraint = getBaseConstraintOfType(source);
+ const constraint = getConstraintOfType(source);
if (constraint) {
if (result = isRelatedTo(constraint, target, reportErrors)) {
errorInfo = saveErrorInfo;
@@ -8593,7 +8634,7 @@ namespace ts {
// Invoke the callback for each underlying property symbol of the given symbol and return the first
// value that isn't undefined.
function forEachProperty(prop: Symbol, callback: (p: Symbol) => T): T {
- if (getCheckFlags(prop) & CheckFlags.SyntheticProperty) {
+ if (getCheckFlags(prop) & CheckFlags.Synthetic) {
for (const t of (prop).containingType.types) {
const p = getPropertyOfType(t, prop.name);
const result = p && forEachProperty(p, callback);
@@ -9015,11 +9056,19 @@ namespace ts {
return regularNew;
}
+ function getWidenedProperty(prop: Symbol): Symbol {
+ const original = getTypeOfSymbol(prop);
+ const widened = getWidenedType(original);
+ return widened === original ? prop : createSymbolWithType(prop, widened);
+ }
+
function getWidenedTypeOfObjectLiteral(type: Type): Type {
- const members = transformTypeOfMembers(type, prop => {
- const widened = getWidenedType(prop);
- return prop === widened ? prop : widened;
- });
+ const members = createMap();
+ for (const prop of getPropertiesOfObjectType(type)) {
+ // Since get accessors already widen their return value there is no need to
+ // widen accessor based properties here.
+ members.set(prop.name, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop) : prop);
+ };
const stringIndexInfo = getIndexInfoOfType(type, IndexKind.String);
const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number);
return createAnonymousType(type.symbol, members, emptyArray, emptyArray,
@@ -9126,7 +9175,7 @@ namespace ts {
}
function reportErrorsFromWidening(declaration: Declaration, type: Type) {
- if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsWideningType) {
+ if (produceDiagnostics && noImplicitAny && type.flags & TypeFlags.ContainsWideningType) {
// Report implicit any error within type if possible, otherwise report error on declaration
if (!reportWideningErrorsInType(type)) {
reportImplicitAnyError(declaration, type);
@@ -9155,13 +9204,14 @@ namespace ts {
}
}
- function createInferenceContext(signature: Signature, inferUnionTypes: boolean): InferenceContext {
+ function createInferenceContext(signature: Signature, inferUnionTypes: boolean, useAnyForNoInferences: boolean): InferenceContext {
const inferences = map(signature.typeParameters, createTypeInferencesObject);
return {
signature,
inferUnionTypes,
inferences,
inferredTypes: new Array(signature.typeParameters.length),
+ useAnyForNoInferences
};
}
@@ -9575,7 +9625,7 @@ namespace ts {
getInferenceMapper(context)));
}
else {
- inferredType = emptyObjectType;
+ inferredType = context.useAnyForNoInferences ? anyType : emptyObjectType;
}
inferenceSucceeded = true;
@@ -9843,9 +9893,8 @@ namespace ts {
if (flags & TypeFlags.NonPrimitive) {
return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
}
- if (flags & TypeFlags.TypeParameter) {
- const constraint = getConstraintOfTypeParameter(type);
- return getTypeFacts(constraint || emptyObjectType);
+ if (flags & TypeFlags.TypeVariable) {
+ return getTypeFacts(getBaseConstraintOfType(type) || emptyObjectType);
}
if (flags & TypeFlags.UnionOrIntersection) {
return getTypeFactsOfTypes((type).types);
@@ -10065,8 +10114,31 @@ namespace ts {
return f(type) ? type : neverType;
}
- function mapType(type: Type, f: (t: Type) => Type): Type {
- return type.flags & TypeFlags.Union ? getUnionType(map((type).types, f)) : f(type);
+ // Apply a mapping function to a type and return the resulting type. If the source type
+ // is a union type, the mapping function is applied to each constituent type and a union
+ // of the resulting types is returned.
+ function mapType(type: Type, mapper: (t: Type) => Type): Type {
+ if (!(type.flags & TypeFlags.Union)) {
+ return mapper(type);
+ }
+ const types = (type).types;
+ let mappedType: Type;
+ let mappedTypes: Type[];
+ for (const current of types) {
+ const t = mapper(current);
+ if (t) {
+ if (!mappedType) {
+ mappedType = t;
+ }
+ else if (!mappedTypes) {
+ mappedTypes = [mappedType, t];
+ }
+ else {
+ mappedTypes.push(t);
+ }
+ }
+ }
+ return mappedTypes ? getUnionType(mappedTypes) : mappedType;
}
function extractTypesOfKind(type: Type, kind: TypeFlags) {
@@ -10204,14 +10276,11 @@ namespace ts {
return false;
}
- function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node) {
+ function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
let key: string;
- if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
+ if (!reference.flowNode || !couldBeUninitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
return declaredType;
}
- const initialType = assumeInitialized ? declaredType :
- declaredType === autoType || declaredType === autoArrayType ? undefinedType :
- includeFalsyTypes(declaredType, TypeFlags.Undefined);
const visitedFlowStart = visitedFlowCount;
const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
visitedFlowCount = visitedFlowStart;
@@ -10632,8 +10701,16 @@ namespace ts {
// is a supertype of that primitive type. For example, type 'any' can be narrowed
// to one of the primitive types.
const targetType = typeofTypesByName.get(literal.text);
- if (targetType && isTypeSubtypeOf(targetType, type)) {
- return targetType;
+ if (targetType) {
+ if (isTypeSubtypeOf(targetType, type)) {
+ return targetType;
+ }
+ if (type.flags & TypeFlags.TypeVariable) {
+ const constraint = getBaseConstraintOfType(type) || anyType;
+ if (isTypeSubtypeOf(targetType, constraint)) {
+ return getIntersectionType([type, targetType]);
+ }
+ }
}
}
const facts = assumeTrue ?
@@ -10731,10 +10808,9 @@ namespace ts {
// Otherwise, if the candidate type is assignable to the target type, narrow to the candidate
// type. Otherwise, the types are completely unrelated, so narrow to an intersection of the
// two types.
- const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type;
return isTypeSubtypeOf(candidate, type) ? candidate :
isTypeAssignableTo(type, candidate) ? type :
- isTypeAssignableTo(candidate, targetType) ? candidate :
+ isTypeAssignableTo(candidate, type) ? candidate :
getIntersectionType([type, candidate]);
}
@@ -10883,6 +10959,16 @@ namespace ts {
return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 && getTypeOfSymbol(symbol) !== autoArrayType;
}
+ /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
+ function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type {
+ const annotationIncludesUndefined = strictNullChecks &&
+ declaration.kind === SyntaxKind.Parameter &&
+ declaration.initializer &&
+ getFalsyFlags(declaredType) & TypeFlags.Undefined &&
+ !(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
+ return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
+ }
+
function checkIdentifier(node: Identifier): Type {
const symbol = getResolvedSymbol(node);
if (symbol === unknownSymbol) {
@@ -11001,13 +11087,16 @@ namespace ts {
const assumeInitialized = isParameter || isOuterVariable ||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node)) ||
isInAmbientContext(declaration);
- const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
+ const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) :
+ type === autoType || type === autoArrayType ? undefinedType :
+ includeFalsyTypes(type, TypeFlags.Undefined);
+ const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer, !assumeInitialized);
// A variable is considered uninitialized when it is possible to analyze the entire control flow graph
// from declaration to use, and when the variable's declared type doesn't include undefined but the
// control flow based type does include undefined.
if (type === autoType || type === autoArrayType) {
if (flowType === autoType || flowType === autoArrayType) {
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
error(declaration.name, Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(flowType));
error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType));
}
@@ -11267,7 +11356,7 @@ namespace ts {
if (isClassLike(container.parent)) {
const symbol = getSymbolOfNode(container.parent);
const type = hasModifier(container, ModifierFlags.Static) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol)).thisType;
- return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
+ return getFlowTypeOfReference(node, type);
}
if (isInJavaScriptFile(node)) {
@@ -11277,7 +11366,7 @@ namespace ts {
}
}
- if (compilerOptions.noImplicitThis) {
+ if (noImplicitThis) {
// With noImplicitThis, functions may not reference 'this' if it has type 'any'
error(node, Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation);
}
@@ -11502,8 +11591,29 @@ namespace ts {
}
}
+ function getContainingObjectLiteral(func: FunctionLikeDeclaration) {
+ return (func.kind === SyntaxKind.MethodDeclaration ||
+ func.kind === SyntaxKind.GetAccessor ||
+ func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? func.parent :
+ func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment ? func.parent.parent :
+ undefined;
+ }
+
+ function getThisTypeArgument(type: Type): Type {
+ return getObjectFlags(type) & ObjectFlags.Reference && (type).target === globalThisType ? (type).typeArguments[0] : undefined;
+ }
+
+ function getThisTypeFromContextualType(type: Type): Type {
+ return mapType(type, t => {
+ return t.flags & TypeFlags.Intersection ? forEach((t).types, getThisTypeArgument) : getThisTypeArgument(t);
+ });
+ }
+
function getContextualThisParameterType(func: FunctionLikeDeclaration): Type {
- if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) {
+ if (func.kind === SyntaxKind.ArrowFunction) {
+ return undefined;
+ }
+ if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
const contextualSignature = getContextualSignature(func);
if (contextualSignature) {
const thisParameter = contextualSignature.thisParameter;
@@ -11512,6 +11622,40 @@ namespace ts {
}
}
}
+ if (noImplicitThis) {
+ const containingLiteral = getContainingObjectLiteral(func);
+ if (containingLiteral) {
+ // We have an object literal method. Check if the containing object literal has a contextual type
+ // that includes a ThisType. If so, T is the contextual type for 'this'. We continue looking in
+ // any directly enclosing object literals.
+ const contextualType = getApparentTypeOfContextualType(containingLiteral);
+ let literal = containingLiteral;
+ let type = contextualType;
+ while (type) {
+ const thisType = getThisTypeFromContextualType(type);
+ if (thisType) {
+ return instantiateType(thisType, getContextualMapper(containingLiteral));
+ }
+ if (literal.parent.kind !== SyntaxKind.PropertyAssignment) {
+ break;
+ }
+ literal = literal.parent.parent;
+ type = getApparentTypeOfContextualType(literal);
+ }
+ // There was no contextual ThisType for the containing object literal, so the contextual type
+ // for 'this' is the non-null form of the contextual type for the containing object literal or
+ // the type of the object literal itself.
+ return contextualType ? getNonNullableType(contextualType) : checkExpressionCached(containingLiteral);
+ }
+ // In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the
+ // contextual type for 'this' is 'obj'.
+ if (func.parent.kind === SyntaxKind.BinaryExpression && (func.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
+ const target = (func.parent).left;
+ if (target.kind === SyntaxKind.PropertyAccessExpression || target.kind === SyntaxKind.ElementAccessExpression) {
+ return checkExpressionCached((target).expression);
+ }
+ }
+ }
return undefined;
}
@@ -11710,42 +11854,15 @@ namespace ts {
return undefined;
}
- // Apply a mapping function to a contextual type and return the resulting type. If the contextual type
- // is a union type, the mapping function is applied to each constituent type and a union of the resulting
- // types is returned.
- function applyToContextualType(type: Type, mapper: (t: Type) => Type): Type {
- if (!(type.flags & TypeFlags.Union)) {
- return mapper(type);
- }
- const types = (type).types;
- let mappedType: Type;
- let mappedTypes: Type[];
- for (const current of types) {
- const t = mapper(current);
- if (t) {
- if (!mappedType) {
- mappedType = t;
- }
- else if (!mappedTypes) {
- mappedTypes = [mappedType, t];
- }
- else {
- mappedTypes.push(t);
- }
- }
- }
- return mappedTypes ? getUnionType(mappedTypes) : mappedType;
- }
-
function getTypeOfPropertyOfContextualType(type: Type, name: string) {
- return applyToContextualType(type, t => {
+ return mapType(type, t => {
const prop = t.flags & TypeFlags.StructuredType ? getPropertyOfType(t, name) : undefined;
return prop ? getTypeOfSymbol(prop) : undefined;
});
}
function getIndexTypeOfContextualType(type: Type, kind: IndexKind) {
- return applyToContextualType(type, t => getIndexTypeOfStructuredType(t, kind));
+ return mapType(type, t => getIndexTypeOfStructuredType(t, kind));
}
// Return true if the given contextual type is a tuple-like type
@@ -11904,6 +12021,16 @@ namespace ts {
return undefined;
}
+ function getContextualMapper(node: Node) {
+ while (node) {
+ if (node.contextualMapper) {
+ return node.contextualMapper;
+ }
+ node = node.parent;
+ }
+ return identityMapper;
+ }
+
// If the given type is an object or union type, if that type has a single signature, and if
// that signature is non-generic, return the signature. Otherwise return undefined.
function getNonGenericSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
@@ -11994,31 +12121,12 @@ namespace ts {
return result;
}
- /**
- * Detect if the mapper implies an inference context. Specifically, there are 4 possible values
- * for a mapper. Let's go through each one of them:
- *
- * 1. undefined - this means we are not doing inferential typing, but we may do contextual typing,
- * which could cause us to assign a parameter a type
- * 2. identityMapper - means we want to avoid assigning a parameter a type, whether or not we are in
- * inferential typing (context is undefined for the identityMapper)
- * 3. a mapper created by createInferenceMapper - we are doing inferential typing, we want to assign
- * types to parameters and fix type parameters (context is defined)
- * 4. an instantiation mapper created by createTypeMapper or createTypeEraser - this should never be
- * passed as the contextual mapper when checking an expression (context is undefined for these)
- *
- * isInferentialContext is detecting if we are in case 3
- */
- function isInferentialContext(mapper: TypeMapper) {
- return mapper && mapper.context;
- }
-
- function checkSpreadExpression(node: SpreadElement, contextualMapper?: TypeMapper): Type {
+ function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type {
if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.SpreadIncludes);
}
- const arrayOrIterableType = checkExpression(node.expression, contextualMapper);
+ const arrayOrIterableType = checkExpression(node.expression, checkMode);
return checkIteratedTypeOrElementType(arrayOrIterableType, node.expression, /*allowStringInput*/ false, /*allowAsyncIterable*/ false);
}
@@ -12027,7 +12135,7 @@ namespace ts {
(node.kind === SyntaxKind.BinaryExpression && (node).operatorToken.kind === SyntaxKind.EqualsToken);
}
- function checkArrayLiteral(node: ArrayLiteralExpression, contextualMapper?: TypeMapper): Type {
+ function checkArrayLiteral(node: ArrayLiteralExpression, checkMode?: CheckMode): Type {
const elements = node.elements;
let hasSpreadElement = false;
const elementTypes: Type[] = [];
@@ -12046,7 +12154,7 @@ namespace ts {
// get the contextual element type from it. So we do something similar to
// getContextualTypeForElementExpression, which will crucially not error
// if there is no index type / iterated type.
- const restArrayType = checkExpression((e).expression, contextualMapper);
+ const restArrayType = checkExpression((e).expression, checkMode);
const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
getIteratedTypeOrElementType(restArrayType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterable*/ false, /*checkAssignability*/ false);
if (restElementType) {
@@ -12054,7 +12162,7 @@ namespace ts {
}
}
else {
- const type = checkExpressionForMutableLocation(e, contextualMapper);
+ const type = checkExpressionForMutableLocation(e, checkMode);
elementTypes.push(type);
}
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement;
@@ -12169,7 +12277,7 @@ namespace ts {
return createIndexInfo(unionType, /*isReadonly*/ false);
}
- function checkObjectLiteral(node: ObjectLiteralExpression, contextualMapper?: TypeMapper): Type {
+ function checkObjectLiteral(node: ObjectLiteralExpression, checkMode?: CheckMode): Type {
const inDestructuringPattern = isAssignmentTarget(node);
// Grammar checking
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
@@ -12182,6 +12290,7 @@ namespace ts {
const contextualType = getApparentTypeOfContextualType(node);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
+ const isJSObjectLiteral = !contextualType && isInJavaScriptFile(node);
let typeFlags: TypeFlags = 0;
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
@@ -12196,14 +12305,14 @@ namespace ts {
isObjectLiteralMethod(memberDecl)) {
let type: Type;
if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
- type = checkPropertyAssignment(memberDecl, contextualMapper);
+ type = checkPropertyAssignment(memberDecl, checkMode);
}
else if (memberDecl.kind === SyntaxKind.MethodDeclaration) {
- type = checkObjectLiteralMethod(memberDecl, contextualMapper);
+ type = checkObjectLiteralMethod(memberDecl, checkMode);
}
else {
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
- type = checkExpressionForMutableLocation((memberDecl).name, contextualMapper);
+ type = checkExpressionForMutableLocation((memberDecl).name, checkMode);
}
typeFlags |= type.flags;
@@ -12272,7 +12381,7 @@ namespace ts {
// A set accessor declaration is processed in the same manner
// as an ordinary function declaration with a single parameter and a Void return type.
Debug.assert(memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor);
- checkAccessorDeclaration(memberDecl);
+ checkNodeDeferred(memberDecl);
}
if (hasDynamicName(memberDecl)) {
@@ -12319,8 +12428,8 @@ namespace ts {
return createObjectLiteralType();
function createObjectLiteralType() {
- const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
- const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
+ const stringIndexInfo = isJSObjectLiteral ? jsObjectLiteralIndexInfo : hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
+ const numberIndexInfo = hasComputedNumberProperty && !isJSObjectLiteral ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
@@ -12409,7 +12518,7 @@ namespace ts {
* @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral,
* which also calls getSpreadType.
*/
- function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, filter?: (symbol: Symbol) => boolean, contextualMapper?: TypeMapper) {
+ function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, filter?: (symbol: Symbol) => boolean, checkMode?: CheckMode) {
const attributes = openingLikeElement.attributes;
let attributesTable = createMap();
let spread: Type = emptyObjectType;
@@ -12418,7 +12527,7 @@ namespace ts {
const member = attributeDecl.symbol;
if (isJsxAttribute(attributeDecl)) {
const exprType = attributeDecl.initializer ?
- checkExpression(attributeDecl.initializer, contextualMapper) :
+ checkExpression(attributeDecl.initializer, checkMode) :
trueType; // is sugar for
const attributeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
@@ -12489,8 +12598,8 @@ namespace ts {
* (See "checkApplicableSignatureForJsxOpeningLikeElement" for how the function is used)
* @param node a JSXAttributes to be resolved of its type
*/
- function checkJsxAttributes(node: JsxAttributes, contextualMapper?: TypeMapper) {
- return createJsxAttributesTypeFromAttributesProperty(node.parent as JsxOpeningLikeElement, /*filter*/ undefined, contextualMapper);
+ function checkJsxAttributes(node: JsxAttributes, checkMode?: CheckMode) {
+ return createJsxAttributesTypeFromAttributesProperty(node.parent as JsxOpeningLikeElement, /*filter*/ undefined, checkMode);
}
function getJsxType(name: string) {
@@ -12531,7 +12640,7 @@ namespace ts {
return links.resolvedSymbol = unknownSymbol;
}
else {
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, JsxNames.IntrinsicElements);
}
return links.resolvedSymbol = unknownSymbol;
@@ -12919,7 +13028,7 @@ namespace ts {
}
if (jsxElementType === undefined) {
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
error(errorNode, Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist);
}
}
@@ -12983,9 +13092,9 @@ namespace ts {
}
}
- function checkJsxExpression(node: JsxExpression, contextualMapper?: TypeMapper) {
+ function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
if (node.expression) {
- const type = checkExpression(node.expression, contextualMapper);
+ const type = checkExpression(node.expression, checkMode);
if (node.dotDotDotToken && type !== anyType && !isArrayType(type)) {
error(node, Diagnostics.JSX_spread_child_must_be_an_array_type, node.toString(), typeToString(type));
}
@@ -13007,7 +13116,7 @@ namespace ts {
const flags = getCombinedModifierFlags(s.valueDeclaration);
return s.parent && s.parent.flags & SymbolFlags.Class ? flags : flags & ~ModifierFlags.AccessibilityModifier;
}
- if (getCheckFlags(s) & CheckFlags.SyntheticProperty) {
+ if (getCheckFlags(s) & CheckFlags.Synthetic) {
const checkFlags = (s).checkFlags;
const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private :
checkFlags & CheckFlags.ContainsPublic ? ModifierFlags.Public :
@@ -13025,6 +13134,10 @@ namespace ts {
return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : 0;
}
+ function isMethodLike(symbol: Symbol) {
+ return !!(symbol.flags & SymbolFlags.Method || getCheckFlags(symbol) & CheckFlags.SyntheticMethod);
+ }
+
/**
* Check whether the requested property access is valid.
* Returns true if node is a valid property access, and false otherwise.
@@ -13054,11 +13167,11 @@ namespace ts {
// where this references the constructor function object of a derived class,
// a super property access is permitted and must specify a public static member function of the base class.
if (languageVersion < ScriptTarget.ES2015) {
- const propKind = getDeclarationKindFromSymbol(prop);
- if (propKind !== SyntaxKind.MethodDeclaration && propKind !== SyntaxKind.MethodSignature) {
- // `prop` refers to a *property* declared in the super class
- // rather than a *method*, so it does not satisfy the above criteria.
-
+ const hasNonMethodDeclaration = forEachProperty(prop, p => {
+ const propKind = getDeclarationKindFromSymbol(p);
+ return propKind !== SyntaxKind.MethodDeclaration && propKind !== SyntaxKind.MethodSignature;
+ });
+ if (hasNonMethodDeclaration) {
error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
return false;
}
@@ -13239,7 +13352,7 @@ namespace ts {
!(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
return propType;
}
- const flowType = getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
+ const flowType = getFlowTypeOfReference(node, propType);
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
}
@@ -13564,7 +13677,7 @@ namespace ts {
// Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec)
function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature {
- const context = createInferenceContext(signature, /*inferUnionTypes*/ true);
+ const context = createInferenceContext(signature, /*inferUnionTypes*/ true, /*useAnyForNoInferences*/ false);
forEachMatchingParameterType(contextualSignature, signature, (source, target) => {
// Type parameters from outer context referenced by source type are fixed by instantiation of the source type
inferTypesWithContext(context, instantiateType(source, contextualMapper), target);
@@ -14265,7 +14378,7 @@ namespace ts {
let candidate: Signature;
let typeArgumentsAreValid: boolean;
const inferenceContext = originalCandidate.typeParameters
- ? createInferenceContext(originalCandidate, /*inferUnionTypes*/ false)
+ ? createInferenceContext(originalCandidate, /*inferUnionTypes*/ false, /*useAnyForNoInferences*/ isInJavaScriptFile(node))
: undefined;
while (true) {
@@ -14742,7 +14855,7 @@ namespace ts {
if (funcSymbol && funcSymbol.members && funcSymbol.flags & SymbolFlags.Function) {
return getInferredClassType(funcSymbol);
}
- else if (compilerOptions.noImplicitAny) {
+ else if (noImplicitAny) {
error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type);
}
return anyType;
@@ -14846,9 +14959,9 @@ namespace ts {
return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : neverType;
}
- function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
+ function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper, checkMode: CheckMode) {
const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
- if (isInferentialContext(mapper)) {
+ if (checkMode === CheckMode.Inferential) {
for (let i = 0; i < len; i++) {
const declaration = signature.parameters[i].valueDeclaration;
if (declaration.type) {
@@ -14862,21 +14975,21 @@ namespace ts {
if (!parameter) {
signature.thisParameter = createSymbolWithType(context.thisParameter, undefined);
}
- assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper);
+ assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper, checkMode);
}
}
for (let i = 0; i < len; i++) {
const parameter = signature.parameters[i];
if (!(parameter.valueDeclaration).type) {
const contextualParameterType = getTypeAtPosition(context, i);
- assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
+ assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper, checkMode);
}
}
if (signature.hasRestParameter && isRestParameterIndex(context, signature.parameters.length - 1)) {
const parameter = lastOrUndefined(signature.parameters);
if (!(parameter.valueDeclaration).type) {
const contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
- assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
+ assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper, checkMode);
}
}
}
@@ -14896,7 +15009,7 @@ namespace ts {
}
}
- function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper) {
+ function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper, checkMode: CheckMode) {
const links = getSymbolLinks(parameter);
if (!links.type) {
links.type = instantiateType(contextualType, mapper);
@@ -14908,7 +15021,7 @@ namespace ts {
}
assignBindingElementTypes(parameter.valueDeclaration);
}
- else if (isInferentialContext(mapper)) {
+ else if (checkMode === CheckMode.Inferential) {
// Even if the parameter already has a type, it might be because it was given a type while
// processing the function as an argument to a prior signature during overload resolution.
// If this was the case, it may have caused some type parameters to be fixed. So here,
@@ -14976,7 +15089,7 @@ namespace ts {
return promiseType;
}
- function getReturnTypeFromBody(func: FunctionLikeDeclaration, contextualMapper?: TypeMapper): Type {
+ function getReturnTypeFromBody(func: FunctionLikeDeclaration, checkMode?: CheckMode): Type {
const contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func);
if (!func.body) {
return unknownType;
@@ -14985,7 +15098,7 @@ namespace ts {
const functionFlags = getFunctionFlags(func);
let type: Type;
if (func.body.kind !== SyntaxKind.Block) {
- type = checkExpressionCached(func.body, contextualMapper);
+ type = checkExpressionCached(func.body, checkMode);
if (functionFlags & FunctionFlags.Async) {
// From within an async function you can return either a non-promise value or a promise. Any
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
@@ -14997,12 +15110,12 @@ namespace ts {
else {
let types: Type[];
if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function
- types = checkAndAggregateYieldOperandTypes(func, contextualMapper);
+ types = checkAndAggregateYieldOperandTypes(func, checkMode);
if (types.length === 0) {
const iterableIteratorAny = functionFlags & FunctionFlags.Async
? createAsyncIterableIteratorType(anyType) // AsyncGenerator function
: createIterableIteratorType(anyType); // Generator function
- if (compilerOptions.noImplicitAny) {
+ if (noImplicitAny) {
error(func.asteriskToken,
Diagnostics.Generator_implicitly_has_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type, typeToString(iterableIteratorAny));
}
@@ -15010,7 +15123,7 @@ namespace ts {
}
}
else {
- types = checkAndAggregateReturnExpressionTypes(func, contextualMapper);
+ types = checkAndAggregateReturnExpressionTypes(func, checkMode);
if (!types) {
// For an async function, the return type will not be never, but rather a Promise for never.
return functionFlags & FunctionFlags.Async
@@ -15054,13 +15167,13 @@ namespace ts {
: widenedType; // Generator function, AsyncGenerator function, or normal function
}
- function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, contextualMapper: TypeMapper): Type[] {
+ function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode): Type[] {
const aggregatedTypes: Type[] = [];
const functionFlags = getFunctionFlags(func);
forEachYieldExpression(func.body, yieldExpression => {
const expr = yieldExpression.expression;
if (expr) {
- let type = checkExpressionCached(expr, contextualMapper);
+ let type = checkExpressionCached(expr, checkMode);
if (yieldExpression.asteriskToken) {
// A yield* expression effectively yields everything that its operand yields
type = checkIteratedTypeOrElementType(type, yieldExpression.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
@@ -15100,7 +15213,7 @@ namespace ts {
return true;
}
- function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, contextualMapper: TypeMapper): Type[] {
+ function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, checkMode: CheckMode): Type[] {
const functionFlags = getFunctionFlags(func);
const aggregatedTypes: Type[] = [];
let hasReturnWithNoExpression = functionHasImplicitReturn(func);
@@ -15108,7 +15221,7 @@ namespace ts {
forEachReturnStatement(func.body, returnStatement => {
const expr = returnStatement.expression;
if (expr) {
- let type = checkExpressionCached(expr, contextualMapper);
+ let type = checkExpressionCached(expr, checkMode);
if (functionFlags & FunctionFlags.Async) {
// From within an async function you can return either a non-promise value or a promise. Any
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
@@ -15195,7 +15308,7 @@ namespace ts {
}
}
- function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, contextualMapper?: TypeMapper): Type {
+ function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, checkMode?: CheckMode): Type {
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
// Grammar checking
@@ -15205,7 +15318,7 @@ namespace ts {
}
// The identityMapper object is used to indicate that function expressions are wildcards
- if (contextualMapper === identityMapper && isContextSensitive(node)) {
+ if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) {
checkNodeDeferred(node);
return anyFunctionType;
}
@@ -15213,7 +15326,7 @@ namespace ts {
const links = getNodeLinks(node);
const type = getTypeOfSymbol(node.symbol);
const contextSensitive = isContextSensitive(node);
- const mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper);
+ const mightFixTypeParameters = contextSensitive && checkMode === CheckMode.Inferential;
// Check if function expression is contextually typed and assign parameter types if so.
// See the comment in assignTypeToParameterAndFixTypeParameters to understand why we need to
@@ -15229,10 +15342,10 @@ namespace ts {
if (contextualSignature) {
const signature = getSignaturesOfType(type, SignatureKind.Call)[0];
if (contextSensitive) {
- assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
+ assignContextualParameterTypes(signature, contextualSignature, getContextualMapper(node), checkMode);
}
if (mightFixTypeParameters || !node.type && !signature.resolvedReturnType) {
- const returnType = getReturnTypeFromBody(node, contextualMapper);
+ const returnType = getReturnTypeFromBody(node, checkMode);
if (!signature.resolvedReturnType) {
signature.resolvedReturnType = returnType;
}
@@ -15608,7 +15721,7 @@ namespace ts {
}
}
- function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type {
+ function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type {
if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Read);
}
@@ -15619,13 +15732,13 @@ namespace ts {
const elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false, /*allowAsyncIterable*/ false) || unknownType;
const elements = node.elements;
for (let i = 0; i < elements.length; i++) {
- checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, elementType, contextualMapper);
+ checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, elementType, checkMode);
}
return sourceType;
}
function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type,
- elementIndex: number, elementType: Type, contextualMapper?: TypeMapper) {
+ elementIndex: number, elementType: Type, checkMode?: CheckMode) {
const elements = node.elements;
const element = elements[elementIndex];
if (element.kind !== SyntaxKind.OmittedExpression) {
@@ -15637,7 +15750,7 @@ namespace ts {
? getTypeOfPropertyOfType(sourceType, propName)
: elementType;
if (type) {
- return checkDestructuringAssignment(element, type, contextualMapper);
+ return checkDestructuringAssignment(element, type, checkMode);
}
else {
// We still need to check element expression here because we may need to set appropriate flag on the expression
@@ -15661,7 +15774,7 @@ namespace ts {
error((restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
else {
- return checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper);
+ return checkDestructuringAssignment(restExpression, createArrayType(elementType), checkMode);
}
}
}
@@ -15669,7 +15782,7 @@ namespace ts {
return undefined;
}
- function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, contextualMapper?: TypeMapper): Type {
+ function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, checkMode?: CheckMode): Type {
let target: Expression;
if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) {
const prop = exprOrAssignment;
@@ -15680,7 +15793,7 @@ namespace ts {
!(getFalsyFlags(checkExpression(prop.objectAssignmentInitializer)) & TypeFlags.Undefined)) {
sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined);
}
- checkBinaryLikeExpression(prop.name, prop.equalsToken, prop.objectAssignmentInitializer, contextualMapper);
+ checkBinaryLikeExpression(prop.name, prop.equalsToken, prop.objectAssignmentInitializer, checkMode);
}
target = (exprOrAssignment).name;
}
@@ -15689,20 +15802,20 @@ namespace ts {
}
if (target.kind === SyntaxKind.BinaryExpression && (target).operatorToken.kind === SyntaxKind.EqualsToken) {
- checkBinaryExpression(target, contextualMapper);
+ checkBinaryExpression(target, checkMode);
target = (target).left;
}
if (target.kind === SyntaxKind.ObjectLiteralExpression) {
return checkObjectLiteralAssignment(target, sourceType);
}
if (target.kind === SyntaxKind.ArrayLiteralExpression) {
- return checkArrayLiteralAssignment(target, sourceType, contextualMapper);
+ return checkArrayLiteralAssignment(target, sourceType, checkMode);
}
- return checkReferenceAssignment(target, sourceType, contextualMapper);
+ return checkReferenceAssignment(target, sourceType, checkMode);
}
- function checkReferenceAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type {
- const targetType = checkExpression(target, contextualMapper);
+ function checkReferenceAssignment(target: Expression, sourceType: Type, checkMode?: CheckMode): Type {
+ const targetType = checkExpression(target, checkMode);
const error = target.parent.kind === SyntaxKind.SpreadAssignment ?
Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access :
Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access;
@@ -15790,17 +15903,17 @@ namespace ts {
getUnionType([type1, type2], /*subtypeReduction*/ true);
}
- function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) {
- return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, contextualMapper, node);
+ function checkBinaryExpression(node: BinaryExpression, checkMode?: CheckMode) {
+ return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, checkMode, node);
}
- function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, contextualMapper?: TypeMapper, errorNode?: Node) {
+ function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, checkMode?: CheckMode, errorNode?: Node) {
const operator = operatorToken.kind;
if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) {
- return checkDestructuringAssignment(left, checkExpression(right, contextualMapper), contextualMapper);
+ return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode);
}
- let leftType = checkExpression(left, contextualMapper);
- let rightType = checkExpression(right, contextualMapper);
+ let leftType = checkExpression(left, checkMode);
+ let rightType = checkExpression(right, checkMode);
switch (operator) {
case SyntaxKind.AsteriskToken:
case SyntaxKind.AsteriskAsteriskToken:
@@ -16067,10 +16180,10 @@ namespace ts {
return anyType;
}
- function checkConditionalExpression(node: ConditionalExpression, contextualMapper?: TypeMapper): Type {
+ function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
checkExpression(node.condition);
- const type1 = checkExpression(node.whenTrue, contextualMapper);
- const type2 = checkExpression(node.whenFalse, contextualMapper);
+ const type1 = checkExpression(node.whenTrue, checkMode);
+ const type2 = checkExpression(node.whenFalse, checkMode);
return getBestChoiceType(type1, type2);
}
@@ -16103,15 +16216,20 @@ namespace ts {
return stringType;
}
- function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper?: TypeMapper): Type {
+ function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper: TypeMapper): Type {
const saveContextualType = node.contextualType;
+ const saveContextualMapper = node.contextualMapper;
node.contextualType = contextualType;
- const result = checkExpression(node, contextualMapper);
+ node.contextualMapper = contextualMapper;
+ const checkMode = contextualMapper === identityMapper ? CheckMode.SkipContextSensitive :
+ contextualMapper ? CheckMode.Inferential : CheckMode.Normal;
+ const result = checkExpression(node, checkMode);
node.contextualType = saveContextualType;
+ node.contextualMapper = saveContextualMapper;
return result;
}
- function checkExpressionCached(node: Expression, contextualMapper?: TypeMapper): Type {
+ function checkExpressionCached(node: Expression, checkMode?: CheckMode): 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
@@ -16119,7 +16237,7 @@ namespace ts {
// to the top of the stack ensures all transient types are computed from a known point.
const saveFlowLoopStart = flowLoopStart;
flowLoopStart = flowLoopCount;
- links.resolvedType = checkExpression(node, contextualMapper);
+ links.resolvedType = checkExpression(node, checkMode);
flowLoopStart = saveFlowLoopStart;
}
return links.resolvedType;
@@ -16140,7 +16258,7 @@ namespace ts {
function isLiteralContextualType(contextualType: Type) {
if (contextualType) {
if (contextualType.flags & TypeFlags.TypeVariable) {
- const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType;
+ const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType;
// If the type parameter is constrained to the base primitive type we're checking for,
// consider this a literal context. For example, given a type parameter 'T extends string',
// this causes us to infer string literal types for T.
@@ -16154,12 +16272,12 @@ namespace ts {
return false;
}
- function checkExpressionForMutableLocation(node: Expression, contextualMapper?: TypeMapper): Type {
- const type = checkExpression(node, contextualMapper);
+ function checkExpressionForMutableLocation(node: Expression, checkMode?: CheckMode): Type {
+ const type = checkExpression(node, checkMode);
return isTypeAssertion(node) || isLiteralContextualType(getContextualType(node)) ? type : getWidenedLiteralType(type);
}
- function checkPropertyAssignment(node: PropertyAssignment, contextualMapper?: TypeMapper): Type {
+ function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type {
// Do not use hasDynamicName here, because that returns false for well known symbols.
// We want to perform checkComputedPropertyName for all computed properties, including
// well known symbols.
@@ -16167,10 +16285,10 @@ namespace ts {
checkComputedPropertyName(node.name);
}
- return checkExpressionForMutableLocation((node).initializer, contextualMapper);
+ return checkExpressionForMutableLocation((node).initializer, checkMode);
}
- function checkObjectLiteralMethod(node: MethodDeclaration, contextualMapper?: TypeMapper): Type {
+ function checkObjectLiteralMethod(node: MethodDeclaration, checkMode?: CheckMode): Type {
// Grammar checking
checkGrammarMethod(node);
@@ -16181,19 +16299,19 @@ namespace ts {
checkComputedPropertyName(node.name);
}
- const uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper);
- return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper);
+ const uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, checkMode);
+ return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
}
- function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) {
- if (isInferentialContext(contextualMapper)) {
+ function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, checkMode?: CheckMode) {
+ if (checkMode === CheckMode.Inferential) {
const signature = getSingleCallSignature(type);
if (signature && signature.typeParameters) {
const contextualType = getApparentTypeOfContextualType(node);
if (contextualType) {
const contextualSignature = getSingleCallSignature(contextualType);
if (contextualSignature && !contextualSignature.typeParameters) {
- return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper));
+ return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, getContextualMapper(node)));
}
}
}
@@ -16229,14 +16347,14 @@ namespace ts {
// object, it serves as an indicator that all contained function and arrow expressions should be considered to
// have the wildcard function type; this form of type check is used during overload resolution to exclude
// contextually typed function and arrow expressions in the initial phase.
- function checkExpression(node: Expression | QualifiedName, contextualMapper?: TypeMapper): Type {
+ function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode): Type {
let type: Type;
if (node.kind === SyntaxKind.QualifiedName) {
type = checkQualifiedName(node);
}
else {
- const uninstantiatedType = checkExpressionWorker(node, contextualMapper);
- type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper);
+ const uninstantiatedType = checkExpressionWorker(node, checkMode);
+ type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
}
if (isConstEnumObjectType(type)) {
@@ -16256,7 +16374,7 @@ namespace ts {
return type;
}
- function checkExpressionWorker(node: Expression, contextualMapper: TypeMapper): Type {
+ function checkExpressionWorker(node: Expression, checkMode: CheckMode): Type {
switch (node.kind) {
case SyntaxKind.Identifier:
return checkIdentifier(node);
@@ -16278,9 +16396,9 @@ namespace ts {
case SyntaxKind.RegularExpressionLiteral:
return globalRegExpType;
case SyntaxKind.ArrayLiteralExpression:
- return checkArrayLiteral(node, contextualMapper);
+ return checkArrayLiteral(node, checkMode);
case SyntaxKind.ObjectLiteralExpression:
- return checkObjectLiteral(node, contextualMapper);
+ return checkObjectLiteral(node, checkMode);
case SyntaxKind.PropertyAccessExpression:
return checkPropertyAccessExpression(node);
case SyntaxKind.ElementAccessExpression:
@@ -16291,12 +16409,12 @@ namespace ts {
case SyntaxKind.TaggedTemplateExpression:
return checkTaggedTemplateExpression(node);
case SyntaxKind.ParenthesizedExpression:
- return checkExpression((node).expression, contextualMapper);
+ return checkExpression((node).expression, checkMode);
case SyntaxKind.ClassExpression:
return checkClassExpression(node);
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
- return checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper);
+ return checkFunctionExpressionOrObjectLiteralMethod(node, checkMode);
case SyntaxKind.TypeOfExpression:
return checkTypeOfExpression(node);
case SyntaxKind.TypeAssertionExpression:
@@ -16317,23 +16435,23 @@ namespace ts {
case SyntaxKind.PostfixUnaryExpression:
return checkPostfixUnaryExpression(node);
case SyntaxKind.BinaryExpression:
- return checkBinaryExpression(node, contextualMapper);
+ return checkBinaryExpression(node, checkMode);
case SyntaxKind.ConditionalExpression:
- return checkConditionalExpression(node, contextualMapper);
+ return checkConditionalExpression(node, checkMode);
case SyntaxKind.SpreadElement:
- return checkSpreadExpression(node, contextualMapper);
+ return checkSpreadExpression(node, checkMode);
case SyntaxKind.OmittedExpression:
return undefinedWideningType;
case SyntaxKind.YieldExpression:
return checkYieldExpression(node);
case SyntaxKind.JsxExpression:
- return checkJsxExpression(node, contextualMapper);
+ return checkJsxExpression(node, checkMode);
case SyntaxKind.JsxElement:
return checkJsxElement(node);
case SyntaxKind.JsxSelfClosingElement:
return checkJsxSelfClosingElement(node);
case SyntaxKind.JsxAttributes:
- return checkJsxAttributes(node, contextualMapper);
+ return checkJsxAttributes(node, checkMode);
case SyntaxKind.JsxOpeningElement:
Debug.fail("Shouldn't ever directly check a JsxOpeningElement");
}
@@ -16546,7 +16664,7 @@ namespace ts {
if (produceDiagnostics) {
checkCollisionWithArgumentsInGeneratedCode(node);
- if (compilerOptions.noImplicitAny && !node.type) {
+ if (noImplicitAny && !node.type) {
switch (node.kind) {
case SyntaxKind.ConstructSignature:
error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type);
@@ -16927,13 +17045,8 @@ namespace ts {
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType);
}
}
- if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) {
- checkSourceElement(node.body);
- registerForUnusedIdentifiersCheck(node);
- }
- else {
- checkNodeDeferred(node);
- }
+ checkSourceElement(node.body);
+ registerForUnusedIdentifiersCheck(node);
}
function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) {
@@ -16944,11 +17057,6 @@ namespace ts {
}
}
- function checkAccessorDeferred(node: AccessorDeclaration) {
- checkSourceElement(node.body);
- registerForUnusedIdentifiersCheck(node);
- }
-
function checkMissingDeclaration(node: Node) {
checkDecorators(node);
}
@@ -17040,7 +17148,7 @@ namespace ts {
// Check if we're indexing with a numeric type and the object type is a generic
// type with a constraint that has a numeric index signature.
if (maybeTypeOfKind(objectType, TypeFlags.TypeVariable) && isTypeOfKind(indexType, TypeFlags.NumberLike)) {
- const constraint = getBaseConstraintOfType(objectType);
+ const constraint = getBaseConstraintOfType(objectType);
if (constraint && getIndexInfoOfType(constraint, IndexKind.Number)) {
return type;
}
@@ -17858,7 +17966,7 @@ namespace ts {
if (produceDiagnostics && !node.type) {
// Report an implicit any error if there is no body, no explicit return type, and node is not a private method
// in an ambient context
- if (compilerOptions.noImplicitAny && nodeIsMissing(node.body) && !isPrivateWithinAmbient(node)) {
+ if (noImplicitAny && nodeIsMissing(node.body) && !isPrivateWithinAmbient(node)) {
reportImplicitAnyError(node, anyType);
}
@@ -19597,7 +19705,7 @@ namespace ts {
else {
// derived overrides base.
const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived);
- if ((baseDeclarationFlags & ModifierFlags.Private) || (derivedDeclarationFlags & ModifierFlags.Private)) {
+ if (baseDeclarationFlags & ModifierFlags.Private || derivedDeclarationFlags & ModifierFlags.Private) {
// either base or derived property is private - not override, skip it
continue;
}
@@ -19607,28 +19715,24 @@ namespace ts {
continue;
}
- if ((base.flags & derived.flags & SymbolFlags.Method) || ((base.flags & SymbolFlags.PropertyOrAccessor) && (derived.flags & SymbolFlags.PropertyOrAccessor))) {
+ if (isMethodLike(base) && isMethodLike(derived) || base.flags & SymbolFlags.PropertyOrAccessor && derived.flags & SymbolFlags.PropertyOrAccessor) {
// method is overridden with method or property/accessor is overridden with property/accessor - correct case
continue;
}
let errorMessage: DiagnosticMessage;
- if (base.flags & SymbolFlags.Method) {
+ if (isMethodLike(base)) {
if (derived.flags & SymbolFlags.Accessor) {
errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor;
}
else {
- Debug.assert((derived.flags & SymbolFlags.Property) !== 0);
errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property;
}
}
else if (base.flags & SymbolFlags.Property) {
- Debug.assert((derived.flags & SymbolFlags.Method) !== 0);
errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function;
}
else {
- Debug.assert((base.flags & SymbolFlags.Accessor) !== 0);
- Debug.assert((derived.flags & SymbolFlags.Method) !== 0);
errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function;
}
@@ -20615,7 +20719,7 @@ namespace ts {
break;
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
- checkAccessorDeferred(node);
+ checkAccessorDeclaration(node);
break;
case SyntaxKind.ClassExpression:
checkClassExpressionDeferred(node);
@@ -21287,7 +21391,7 @@ namespace ts {
}
function getRootSymbols(symbol: Symbol): Symbol[] {
- if (getCheckFlags(symbol) & CheckFlags.SyntheticProperty) {
+ if (getCheckFlags(symbol) & CheckFlags.Synthetic) {
const symbols: Symbol[] = [];
const name = symbol.name;
forEach(getSymbolLinks(symbol).containingType.types, t => {
@@ -21972,9 +22076,9 @@ namespace ts {
anyArrayType = createArrayType(anyType);
autoArrayType = createArrayType(autoType);
- const symbol = getGlobalSymbol("ReadonlyArray", SymbolFlags.Type, /*diagnostic*/ undefined);
- globalReadonlyArrayType = symbol && getTypeOfGlobalSymbol(symbol, /*arity*/ 1);
+ globalReadonlyArrayType = getGlobalTypeOrUndefined("ReadonlyArray", /*arity*/ 1);
anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType;
+ globalThisType = getGlobalTypeOrUndefined("ThisType", /*arity*/ 1);
}
function checkExternalEmitHelpers(location: Node, helpers: ExternalEmitHelpers) {
diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts
index 6b4e9ff590e..4b3dc23d565 100644
--- a/src/compiler/commandLineParser.ts
+++ b/src/compiler/commandLineParser.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
///
@@ -467,6 +467,11 @@ namespace ts {
type: "boolean",
description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file
},
+ {
+ name: "strict",
+ type: "boolean",
+ description: Diagnostics.Enable_all_strict_type_checks
+ },
{
// A list of plugins to load in the language service
name: "plugins",
@@ -520,7 +525,7 @@ namespace ts {
export const defaultInitCompilerOptions: CompilerOptions = {
module: ModuleKind.CommonJS,
target: ScriptTarget.ES5,
- noImplicitAny: false,
+ strict: true,
sourceMap: false,
};
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index c3c0ba77fe4..c380a39611d 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -1,4 +1,4 @@
-///
+///
///
namespace ts {
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 75aa5d25f72..919158645a4 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -2413,10 +2413,6 @@
"category": "Error",
"code": 5012
},
- "Unsupported file encoding.": {
- "category": "Error",
- "code": 5013
- },
"Failed to parse file '{0}': {1}.": {
"category": "Error",
"code": 5014
@@ -3045,6 +3041,10 @@
"category": "Message",
"code": 6149
},
+ "Enable all strict type checks.": {
+ "category": "Message",
+ "code": 6150
+ },
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index adc46dcfa1d..9fb7e134e85 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
///
@@ -199,6 +199,8 @@ namespace ts {
onEmitHelpers,
onSetSourceFile,
substituteNode,
+ onBeforeEmitNodeArray,
+ onAfterEmitNodeArray
} = handlers;
const newLine = getNewLineCharacter(printerOptions);
@@ -635,6 +637,11 @@ namespace ts {
if (isExpression(node)) {
return pipelineEmitExpression(trySubstituteNode(EmitHint.Expression, node));
}
+
+ if (isToken(node)) {
+ writeTokenText(kind);
+ return;
+ }
}
function pipelineEmitExpression(node: Node): void {
@@ -814,8 +821,8 @@ namespace ts {
writeIfPresent(node.dotDotDotToken, "...");
emit(node.name);
writeIfPresent(node.questionToken, "?");
- emitExpressionWithPrefix(" = ", node.initializer);
emitWithPrefix(": ", node.type);
+ emitExpressionWithPrefix(" = ", node.initializer);
}
function emitDecorator(decorator: Decorator) {
@@ -1548,6 +1555,10 @@ namespace ts {
emitSignatureAndBody(node, emitSignatureHead);
}
+ function emitBlockCallback(_hint: EmitHint, body: Node): void {
+ emitBlockFunctionBody(body);
+ }
+
function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) {
const body = node.body;
if (body) {
@@ -1559,12 +1570,22 @@ namespace ts {
if (getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
emitSignatureHead(node);
- emitBlockFunctionBody(body);
+ if (onEmitNode) {
+ onEmitNode(EmitHint.Unspecified, body, emitBlockCallback);
+ }
+ else {
+ emitBlockFunctionBody(body);
+ }
}
else {
pushNameGenerationScope();
emitSignatureHead(node);
- emitBlockFunctionBody(body);
+ if (onEmitNode) {
+ onEmitNode(EmitHint.Unspecified, body, emitBlockCallback);
+ }
+ else {
+ emitBlockFunctionBody(body);
+ }
popNameGenerationScope();
}
@@ -2243,6 +2264,10 @@ namespace ts {
write(getOpeningBracket(format));
}
+ if (onBeforeEmitNodeArray) {
+ onBeforeEmitNodeArray(children);
+ }
+
if (isEmpty) {
// Write a line terminator if the parent node was multi-line
if (format & ListFormat.MultiLine) {
@@ -2358,6 +2383,10 @@ namespace ts {
}
}
+ if (onAfterEmitNodeArray) {
+ onAfterEmitNodeArray(children);
+ }
+
if (format & ListFormat.BracketsMask) {
write(getClosingBracket(format));
}
diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts
index cfafaabebff..669c66c4337 100644
--- a/src/compiler/factory.ts
+++ b/src/compiler/factory.ts
@@ -1,4 +1,4 @@
-///
+///
///
namespace ts {
@@ -1099,6 +1099,10 @@ namespace ts {
: node;
}
+ export function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode {
+ return createSynthesizedNode(kind);
+ }
+
export function createFunctionDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
const node = createSynthesizedNode(SyntaxKind.FunctionDeclaration);
node.decorators = asNodeArray(decorators);
diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts
index 1911605a0a6..699919e0566 100644
--- a/src/compiler/moduleNameResolver.ts
+++ b/src/compiler/moduleNameResolver.ts
@@ -1,4 +1,4 @@
-///
+///
///
namespace ts {
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index 308d3a317f9..f2175f385ec 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -1309,7 +1309,7 @@ namespace ts {
case ParsingContext.ObjectBindingElements:
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
case ParsingContext.HeritageClauseElement:
- // If we see { } then only consume it as an expression if it is followed by , or {
+ // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
// That way we won't consume the body of a class in its heritage clause.
if (token() === SyntaxKind.OpenBraceToken) {
return lookAhead(isValidHeritageClauseObjectLiteral);
@@ -2113,7 +2113,7 @@ namespace ts {
return finishNode(node);
}
- function parseTypeParameters(): NodeArray {
+ function parseTypeParameters(): NodeArray | undefined {
if (token() === SyntaxKind.LessThanToken) {
return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
}
@@ -2183,7 +2183,7 @@ namespace ts {
}
function fillSignature(
- returnToken: SyntaxKind,
+ returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
yieldContext: boolean,
awaitContext: boolean,
requireCompleteParameterList: boolean,
@@ -2373,14 +2373,14 @@ namespace ts {
}
function isTypeMemberStart(): boolean {
- let idToken: SyntaxKind;
// Return true if we have the start of a signature member
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
return true;
}
+ let idToken: boolean;
// Eat up all modifiers, but hold on to the last one in case it is actually an identifier
while (isModifierKind(token())) {
- idToken = token();
+ idToken = true;
nextToken();
}
// Index signatures and computed property names are type members
@@ -2389,7 +2389,7 @@ namespace ts {
}
// Try to get the first property-like token following all modifiers
if (isLiteralPropertyName()) {
- idToken = token();
+ idToken = true;
nextToken();
}
// If we were able to get any potential identifier, check that it is
@@ -2497,7 +2497,7 @@ namespace ts {
return finishNode(node);
}
- function parseKeywordAndNoDot(): TypeNode {
+ function parseKeywordAndNoDot(): TypeNode | undefined {
const node = parseTokenNode();
return token() === SyntaxKind.DotToken ? undefined : node;
}
@@ -2635,7 +2635,7 @@ namespace ts {
return parseArrayTypeOrHigher();
}
- function parseUnionOrIntersectionType(kind: SyntaxKind, parseConstituentType: () => TypeNode, operator: SyntaxKind): TypeNode {
+ function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {
parseOptional(operator);
let type = parseConstituentType();
if (token() === operator) {
@@ -3863,6 +3863,9 @@ namespace ts {
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
break;
}
+ else if (token() === SyntaxKind.ConflictMarkerTrivia) {
+ break;
+ }
result.push(parseJsxChild());
}
@@ -5281,8 +5284,8 @@ namespace ts {
*
* In such situations, 'permitInvalidConstAsModifier' should be set to true.
*/
- function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray {
- let modifiers: NodeArray;
+ function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray | undefined {
+ let modifiers: NodeArray | undefined;
while (true) {
const modifierStart = scanner.getStartPos();
const modifierKind = token();
@@ -5422,7 +5425,7 @@ namespace ts {
return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword);
}
- function parseHeritageClauses(): NodeArray {
+ function parseHeritageClauses(): NodeArray | undefined {
// ClassTail[Yield,Await] : (Modified) See 14.5
// ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
@@ -5433,7 +5436,7 @@ namespace ts {
return undefined;
}
- function parseHeritageClause() {
+ function parseHeritageClause(): HeritageClause | undefined {
if (token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword) {
const node = createNode(SyntaxKind.HeritageClause);
node.token = token();
@@ -5459,7 +5462,7 @@ namespace ts {
return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
}
- function parseClassMembers() {
+ function parseClassMembers(): NodeArray {
return parseList(ParsingContext.ClassMembers, parseClassElement);
}
@@ -5618,17 +5621,7 @@ namespace ts {
if (isIdentifier()) {
identifier = parseIdentifier();
if (token() !== SyntaxKind.CommaToken && token() !== SyntaxKind.FromKeyword) {
- // ImportEquals declaration of type:
- // import x = require("mod"); or
- // import x = M.x;
- const importEqualsDeclaration = createNode(SyntaxKind.ImportEqualsDeclaration, fullStart);
- importEqualsDeclaration.decorators = decorators;
- importEqualsDeclaration.modifiers = modifiers;
- importEqualsDeclaration.name = identifier;
- parseExpected(SyntaxKind.EqualsToken);
- importEqualsDeclaration.moduleReference = parseModuleReference();
- parseSemicolon();
- return addJSDocComment(finishNode(importEqualsDeclaration));
+ return parseImportEqualsDeclaration(fullStart, decorators, modifiers, identifier);
}
}
@@ -5652,6 +5645,17 @@ namespace ts {
return finishNode(importDeclaration);
}
+ function parseImportEqualsDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray, identifier: ts.Identifier): ImportEqualsDeclaration {
+ const importEqualsDeclaration = createNode(SyntaxKind.ImportEqualsDeclaration, fullStart);
+ importEqualsDeclaration.decorators = decorators;
+ importEqualsDeclaration.modifiers = modifiers;
+ importEqualsDeclaration.name = identifier;
+ parseExpected(SyntaxKind.EqualsToken);
+ importEqualsDeclaration.moduleReference = parseModuleReference();
+ parseSemicolon();
+ return addJSDocComment(finishNode(importEqualsDeclaration));
+ }
+
function parseImportClause(identifier: Identifier, fullStart: number) {
// ImportClause:
// ImportedDefaultBinding
diff --git a/src/compiler/program.ts b/src/compiler/program.ts
index eb9f0f0e0a1..cffb6df1e3d 100644
--- a/src/compiler/program.ts
+++ b/src/compiler/program.ts
@@ -87,9 +87,6 @@ namespace ts {
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
- // returned by CScript sys environment
- const unsupportedFileEncodingErrorCode = -2147024809;
-
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
let text: string;
try {
@@ -100,9 +97,7 @@ namespace ts {
}
catch (e) {
if (onError) {
- onError(e.number === unsupportedFileEncodingErrorCode
- ? createCompilerDiagnostic(Diagnostics.Unsupported_file_encoding).messageText
- : e.message);
+ onError(e.message);
}
text = "";
}
@@ -290,6 +285,11 @@ namespace ts {
return resolutions;
}
+ interface DiagnosticCache {
+ perFile?: FileMap;
+ allDiagnostics?: Diagnostic[];
+ }
+
export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program {
let program: Program;
let files: SourceFile[] = [];
@@ -298,6 +298,9 @@ namespace ts {
let noDiagnosticsTypeChecker: TypeChecker;
let classifiableNames: Map;
+ const cachedSemanticDiagnosticsForFile: DiagnosticCache = {};
+ const cachedDeclarationDiagnosticsForFile: DiagnosticCache = {};
+
let resolvedTypeReferenceDirectives = createMap();
let fileProcessingDiagnostics = createDiagnosticCollection();
@@ -899,6 +902,10 @@ namespace ts {
}
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
+ return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedSemanticDiagnosticsForFile, getSemanticDiagnosticsForFileNoCache);
+ }
+
+ function getSemanticDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
return runWithCancellationToken(() => {
const typeChecker = getDiagnosticsProducingTypeChecker();
@@ -1094,7 +1101,11 @@ namespace ts {
});
}
- function getDeclarationDiagnosticsWorker(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
+ function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken): Diagnostic[] {
+ return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
+ }
+
+ function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken) {
return runWithCancellationToken(() => {
const resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken);
// Don't actually write any files since we're just getting diagnostics.
@@ -1102,6 +1113,32 @@ namespace ts {
});
}
+ function getAndCacheDiagnostics(
+ sourceFile: SourceFile | undefined,
+ cancellationToken: CancellationToken,
+ cache: DiagnosticCache,
+ getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[]) {
+
+ const cachedResult = sourceFile
+ ? cache.perFile && cache.perFile.get(sourceFile.path)
+ : cache.allDiagnostics;
+
+ if (cachedResult) {
+ return cachedResult;
+ }
+ const result = getDiagnostics(sourceFile, cancellationToken) || emptyArray;
+ if (sourceFile) {
+ if (!cache.perFile) {
+ cache.perFile = createFileMap();
+ }
+ cache.perFile.set(sourceFile.path, result);
+ }
+ else {
+ cache.allDiagnostics = result;
+ }
+ return result;
+ }
+
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
return isDeclarationFile(sourceFile) ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
}
@@ -1630,7 +1667,7 @@ namespace ts {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib"));
}
- if (options.noImplicitUseStrict && options.alwaysStrict) {
+ if (options.noImplicitUseStrict && (options.alwaysStrict === undefined ? options.strict : options.alwaysStrict)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"));
}
diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts
index fb91b0ff5b7..466074bdbcc 100644
--- a/src/compiler/scanner.ts
+++ b/src/compiler/scanner.ts
@@ -333,7 +333,7 @@ namespace ts {
}
/* @internal */
- export function getLineStarts(sourceFile: SourceFile): number[] {
+ export function getLineStarts(sourceFile: SourceFileLike): number[] {
return sourceFile.lineMap || (sourceFile.lineMap = computeLineStarts(sourceFile.text));
}
@@ -1716,7 +1716,14 @@ namespace ts {
while (pos < end) {
pos++;
char = text.charCodeAt(pos);
- if ((char === CharacterCodes.openBrace) || (char === CharacterCodes.lessThan)) {
+ if (char === CharacterCodes.openBrace) {
+ break;
+ }
+ if (char === CharacterCodes.lessThan) {
+ if (isConflictMarkerTrivia(text, pos)) {
+ pos = scanConflictMarkerTrivia(text, pos, error);
+ return token = SyntaxKind.ConflictMarkerTrivia;
+ }
break;
}
}
diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts
index cf50ab6482b..5275d210172 100644
--- a/src/compiler/sys.ts
+++ b/src/compiler/sys.ts
@@ -1,4 +1,4 @@
-///
+///
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
@@ -74,13 +74,6 @@ namespace ts {
return parseInt(version.substring(1, dot));
}
- declare class Enumerator {
- public atEnd(): boolean;
- public moveNext(): boolean;
- public item(): any;
- constructor(o: any);
- }
-
declare var ChakraHost: {
args: string[];
currentDirectory: string;
@@ -104,152 +97,6 @@ namespace ts {
};
export let sys: System = (function() {
-
- function getWScriptSystem(): System {
-
- const fso = new ActiveXObject("Scripting.FileSystemObject");
- const shell = new ActiveXObject("WScript.Shell");
-
- const fileStream = new ActiveXObject("ADODB.Stream");
- fileStream.Type = 2 /*text*/;
-
- const binaryStream = new ActiveXObject("ADODB.Stream");
- binaryStream.Type = 1 /*binary*/;
-
- const args: string[] = [];
- for (let i = 0; i < WScript.Arguments.length; i++) {
- args[i] = WScript.Arguments.Item(i);
- }
-
- function readFile(fileName: string, encoding?: string): string {
- if (!fso.FileExists(fileName)) {
- return undefined;
- }
- fileStream.Open();
- try {
- if (encoding) {
- fileStream.Charset = encoding;
- fileStream.LoadFromFile(fileName);
- }
- else {
- // Load file and read the first two bytes into a string with no interpretation
- fileStream.Charset = "x-ansi";
- fileStream.LoadFromFile(fileName);
- const bom = fileStream.ReadText(2) || "";
- // Position must be at 0 before encoding can be changed
- fileStream.Position = 0;
- // [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8
- fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8";
- }
- // ReadText method always strips byte order mark from resulting string
- return fileStream.ReadText();
- }
- catch (e) {
- throw e;
- }
- finally {
- fileStream.Close();
- }
- }
-
- function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
- fileStream.Open();
- binaryStream.Open();
- try {
- // Write characters in UTF-8 encoding
- fileStream.Charset = "utf-8";
- fileStream.WriteText(data);
- // If we don't want the BOM, then skip it by setting the starting location to 3 (size of BOM).
- // If not, start from position 0, as the BOM will be added automatically when charset==utf8.
- if (writeByteOrderMark) {
- fileStream.Position = 0;
- }
- else {
- fileStream.Position = 3;
- }
- fileStream.CopyTo(binaryStream);
- binaryStream.SaveToFile(fileName, 2 /*overwrite*/);
- }
- finally {
- binaryStream.Close();
- fileStream.Close();
- }
- }
-
- function getNames(collection: any): string[] {
- const result: string[] = [];
- for (const e = new Enumerator(collection); !e.atEnd(); e.moveNext()) {
- result.push(e.item().Name);
- }
- return result.sort();
- }
-
- function getDirectories(path: string): string[] {
- const folder = fso.GetFolder(path);
- return getNames(folder.subfolders);
- }
-
- function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
- try {
- const folder = fso.GetFolder(path || ".");
- const files = getNames(folder.files);
- const directories = getNames(folder.subfolders);
- return { files, directories };
- }
- catch (e) {
- return { files: [], directories: [] };
- }
- }
-
- function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
- return matchFiles(path, extensions, excludes, includes, /*useCaseSensitiveFileNames*/ false, shell.CurrentDirectory, getAccessibleFileSystemEntries);
- }
-
- const wscriptSystem: System = {
- args,
- newLine: "\r\n",
- useCaseSensitiveFileNames: false,
- write(s: string): void {
- WScript.StdOut.Write(s);
- },
- readFile,
- writeFile,
- resolvePath(path: string): string {
- return fso.GetAbsolutePathName(path);
- },
- fileExists(path: string): boolean {
- return fso.FileExists(path);
- },
- directoryExists(path: string) {
- return fso.FolderExists(path);
- },
- createDirectory(directoryName: string) {
- if (!wscriptSystem.directoryExists(directoryName)) {
- fso.CreateFolder(directoryName);
- }
- },
- getExecutingFilePath() {
- return WScript.ScriptFullName;
- },
- getCurrentDirectory() {
- return shell.CurrentDirectory;
- },
- getDirectories,
- getEnvironmentVariable(name: string) {
- return new ActiveXObject("WScript.Shell").ExpandEnvironmentStrings(`%${name}%`);
- },
- readDirectory,
- exit(exitCode?: number): void {
- try {
- WScript.Quit(exitCode);
- }
- catch (e) {
- }
- }
- };
- return wscriptSystem;
- }
-
function getNodeSystem(): System {
const _fs = require("fs");
const _path = require("path");
@@ -355,7 +202,7 @@ namespace ts {
if (len >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
// Big endian UTF-16 byte order mark detected. Since big endian is not supported by node.js,
// flip all byte pairs and treat as little endian.
- len &= ~1;
+ len &= ~1; // Round down to a multiple of 2
for (let i = 0; i < len; i += 2) {
const temp = buffer[i];
buffer[i] = buffer[i + 1];
@@ -646,9 +493,6 @@ namespace ts {
if (typeof ChakraHost !== "undefined") {
sys = getChakraSystem();
}
- else if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
- sys = getWScriptSystem();
- }
else if (typeof process !== "undefined" && process.nextTick && !process.browser && typeof require !== "undefined") {
// process and process.nextTick checks if current environment is node-like
// process.browser check excludes webpack and browserify
diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts
index d51fdb12ac3..bb1732b57ea 100644
--- a/src/compiler/transformer.ts
+++ b/src/compiler/transformer.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
///
diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts
index bb129cd1187..df372fd9a2c 100644
--- a/src/compiler/transformers/destructuring.ts
+++ b/src/compiler/transformers/destructuring.ts
@@ -43,7 +43,7 @@ namespace ts {
let value: Expression;
if (isDestructuringAssignment(node)) {
value = node.right;
- while (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
+ while (isEmptyArrayLiteral(node.left) || isEmptyObjectLiteral(node.left)) {
if (isDestructuringAssignment(value)) {
location = node = value;
value = node.right;
diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts
index 57e85f50f39..e55cfc76db3 100644
--- a/src/compiler/transformers/generators.ts
+++ b/src/compiler/transformers/generators.ts
@@ -1,4 +1,4 @@
-///
+///
///
// Transforms generator functions into a compatible ES5 representation with similar runtime
diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts
index 52c6db707c1..4ef9c674ad9 100644
--- a/src/compiler/transformers/module/module.ts
+++ b/src/compiler/transformers/module/module.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
@@ -55,9 +55,7 @@ namespace ts {
* @param node The SourceFile node.
*/
function transformSourceFile(node: SourceFile) {
- if (isDeclarationFile(node)
- || !(isExternalModule(node)
- || compilerOptions.isolatedModules)) {
+ if (isDeclarationFile(node) || !(isExternalModule(node) || compilerOptions.isolatedModules)) {
return node;
}
@@ -74,6 +72,14 @@ namespace ts {
return aggregateTransformFlags(updated);
}
+
+ function shouldEmitUnderscoreUnderscoreESModule() {
+ if (!currentModuleInfo.exportEquals && isExternalModule(currentSourceFile)) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Transforms a SourceFile into a CommonJS module.
*
@@ -83,9 +89,10 @@ namespace ts {
startLexicalEnvironment();
const statements: Statement[] = [];
- const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
+ const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
+ const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor);
- if (!currentModuleInfo.exportEquals) {
+ if (shouldEmitUnderscoreUnderscoreESModule()) {
append(statements, createUnderscoreUnderscoreESModule());
}
@@ -378,7 +385,7 @@ namespace ts {
const statements: Statement[] = [];
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
- if (!currentModuleInfo.exportEquals) {
+ if (shouldEmitUnderscoreUnderscoreESModule()) {
append(statements, createUnderscoreUnderscoreESModule());
}
diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts
index 7488c51ed91..642ac1ce6fb 100644
--- a/src/compiler/transformers/module/system.ts
+++ b/src/compiler/transformers/module/system.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
@@ -225,7 +225,8 @@ namespace ts {
startLexicalEnvironment();
// Add any prologue directives.
- const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
+ const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
+ const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor);
// var __moduleName = context_1 && context_1.id;
statements.push(
diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts
index e712393b2f0..885f8fad898 100644
--- a/src/compiler/transformers/ts.ts
+++ b/src/compiler/transformers/ts.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
@@ -472,7 +472,8 @@ namespace ts {
}
function visitSourceFile(node: SourceFile) {
- const alwaysStrict = compilerOptions.alwaysStrict && !(isExternalModule(node) && moduleKind === ModuleKind.ES2015);
+ const alwaysStrict = (compilerOptions.alwaysStrict === undefined ? compilerOptions.strict : compilerOptions.alwaysStrict) &&
+ !(isExternalModule(node) && moduleKind === ModuleKind.ES2015);
return updateSourceFileNode(
node,
visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, alwaysStrict));
diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts
index b1ffcff43a4..32b6a90e268 100644
--- a/src/compiler/tsc.ts
+++ b/src/compiler/tsc.ts
@@ -1,4 +1,4 @@
-///
+///
///
namespace ts {
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 53d84118609..26d6730ce55 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -1,4 +1,4 @@
-namespace ts {
+namespace ts {
/**
* Type of objects whose values are all of the same type.
* The `in` and `for-in` operators can *not* be safely used,
@@ -519,6 +519,8 @@
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
/* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding)
/* @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms)
+ /* @internal */ contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
+ /* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type
}
export interface NodeArray extends Array, TextRange {
@@ -963,7 +965,6 @@
export interface Expression extends Node {
_expressionBrand: any;
- contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
}
export interface OmittedExpression extends Expression {
@@ -1812,7 +1813,7 @@
kind: SyntaxKind.ModuleDeclaration;
parent?: ModuleBody | SourceFile;
name: ModuleName;
- body?: ModuleBody | JSDocNamespaceDeclaration | Identifier;
+ body?: ModuleBody | JSDocNamespaceDeclaration;
}
export type NamespaceBody = ModuleBlock | NamespaceDeclaration;
@@ -1837,6 +1838,11 @@
export type ModuleReference = EntityName | ExternalModuleReference;
+ /**
+ * One of:
+ * - import x = require("mod");
+ * - import x = M.x;
+ */
export interface ImportEqualsDeclaration extends DeclarationStatement {
kind: SyntaxKind.ImportEqualsDeclaration;
parent?: SourceFile | ModuleBlock;
@@ -1888,7 +1894,6 @@
export interface NamespaceExportDeclaration extends DeclarationStatement {
kind: SyntaxKind.NamespaceExportDeclaration;
name: Identifier;
- moduleReference: LiteralLikeNode;
}
export interface ExportDeclaration extends DeclarationStatement {
@@ -2204,6 +2209,16 @@
name: string;
}
+ /* @internal */
+ /**
+ * Subset of properties from SourceFile that are used in multiple utility functions
+ */
+ export interface SourceFileLike {
+ readonly text: string;
+ lineMap: number[];
+ }
+
+
// Source files are declarations when they are external modules.
export interface SourceFile extends Declaration {
kind: SyntaxKind.SourceFile;
@@ -2211,7 +2226,7 @@
endOfFileToken: Token;
fileName: string;
- /* internal */ path: Path;
+ /* @internal */ path: Path;
text: string;
amdDependencies: AmdDependency[];
@@ -2810,13 +2825,15 @@
export const enum CheckFlags {
Instantiated = 1 << 0, // Instantiated symbol
SyntheticProperty = 1 << 1, // Property in union or intersection type
- Readonly = 1 << 2, // Readonly transient symbol
- Partial = 1 << 3, // Synthetic property present in some but not all constituents
- HasNonUniformType = 1 << 4, // Synthetic property with non-uniform type in constituents
- ContainsPublic = 1 << 5, // Synthetic property with public constituent(s)
- ContainsProtected = 1 << 6, // Synthetic property with protected constituent(s)
- ContainsPrivate = 1 << 7, // Synthetic property with private constituent(s)
- ContainsStatic = 1 << 8, // Synthetic property with static constituent(s)
+ SyntheticMethod = 1 << 2, // Method in union or intersection type
+ Readonly = 1 << 3, // Readonly transient symbol
+ Partial = 1 << 4, // Synthetic property present in some but not all constituents
+ HasNonUniformType = 1 << 5, // Synthetic property with non-uniform type in constituents
+ ContainsPublic = 1 << 6, // Synthetic property with public constituent(s)
+ ContainsProtected = 1 << 7, // Synthetic property with protected constituent(s)
+ ContainsPrivate = 1 << 8, // Synthetic property with private constituent(s)
+ ContainsStatic = 1 << 9, // Synthetic property with static constituent(s)
+ Synthetic = SyntheticProperty | SyntheticMethod
}
/* @internal */
@@ -3234,6 +3251,7 @@
mapper?: TypeMapper; // Type mapper for this inference context
failedTypeParameterIndex?: number; // Index of type parameter for which inference failed
// It is optional because in contextual signature instantiation, nothing fails
+ useAnyForNoInferences?: boolean; // Use any instead of {} for no inferences
}
/* @internal */
@@ -3308,7 +3326,7 @@
allowSyntheticDefaultImports?: boolean;
allowUnreachableCode?: boolean;
allowUnusedLabels?: boolean;
- alwaysStrict?: boolean;
+ alwaysStrict?: boolean; // Always combine with strict property
baseUrl?: string;
charset?: string;
/* @internal */ configFilePath?: string;
@@ -3344,9 +3362,9 @@
noEmitOnError?: boolean;
noErrorTruncation?: boolean;
noFallthroughCasesInSwitch?: boolean;
- noImplicitAny?: boolean;
+ noImplicitAny?: boolean; // Always combine with strict property
noImplicitReturns?: boolean;
- noImplicitThis?: boolean;
+ noImplicitThis?: boolean; // Always combine with strict property
noUnusedLocals?: boolean;
noUnusedParameters?: boolean;
noImplicitUseStrict?: boolean;
@@ -3369,7 +3387,8 @@
skipDefaultLibCheck?: boolean;
sourceMap?: boolean;
sourceRoot?: string;
- strictNullChecks?: boolean;
+ strict?: boolean;
+ strictNullChecks?: boolean; // Always combine with strict property
/* @internal */ stripInternal?: boolean;
suppressExcessPropertyErrors?: boolean;
suppressImplicitAnyIndexErrors?: boolean;
@@ -4129,6 +4148,8 @@
/*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void;
/*@internal*/ onEmitHelpers?: (node: Node, writeLines: (text: string) => void) => void;
/*@internal*/ onSetSourceFile?: (node: SourceFile) => void;
+ /*@internal*/ onBeforeEmitNodeArray?: (nodes: NodeArray) => void;
+ /*@internal*/ onAfterEmitNodeArray?: (nodes: NodeArray) => void;
}
export interface PrinterOptions {
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index e107c4b669b..030b66813a5 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -1,4 +1,4 @@
-///
+///
/* @internal */
namespace ts {
@@ -184,7 +184,7 @@ namespace ts {
return false;
}
- export function getStartPositionOfLine(line: number, sourceFile: SourceFile): number {
+ export function getStartPositionOfLine(line: number, sourceFile: SourceFileLike): number {
Debug.assert(line >= 0);
return getLineStarts(sourceFile)[line];
}
@@ -204,7 +204,7 @@ namespace ts {
return value !== undefined;
}
- export function getEndLinePosition(line: number, sourceFile: SourceFile): number {
+ export function getEndLinePosition(line: number, sourceFile: SourceFileLike): number {
Debug.assert(line >= 0);
const lineStarts = getLineStarts(sourceFile);
@@ -255,7 +255,11 @@ namespace ts {
return !nodeIsMissing(node);
}
- export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, includeJsDoc?: boolean): number {
+ export function isToken(n: Node): boolean {
+ return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
+ }
+
+ export function getTokenPosOfNode(node: Node, sourceFile?: SourceFileLike, includeJsDoc?: boolean): number {
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
// want to skip trivia because this will launch us forward to the next token.
if (nodeIsMissing(node)) {
@@ -289,7 +293,7 @@ namespace ts {
return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode;
}
- export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
+ export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFileLike): number {
if (nodeIsMissing(node) || !node.decorators) {
return getTokenPosOfNode(node, sourceFile);
}
@@ -1425,6 +1429,21 @@ namespace ts {
return false;
}
+ export function getRightMostAssignedExpression(node: Node) {
+ while (isAssignmentExpression(node, /*excludeCompoundAssignements*/ true)) {
+ node = node.right;
+ }
+ return node;
+ }
+
+ export function isExportsIdentifier(node: Node) {
+ return isIdentifier(node) && node.text === "exports";
+ }
+
+ export function isModuleExportsPropertyAccessExpression(node: Node) {
+ return isPropertyAccessExpression(node) && isIdentifier(node.expression) && node.expression.text === "module" && node.name.text === "exports";
+ }
+
/// 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 {
@@ -2476,7 +2495,7 @@ namespace ts {
return indentStrings[1].length;
}
- export function createTextWriter(newLine: String): EmitTextWriter {
+ export function createTextWriter(newLine: string): EmitTextWriter {
let output: string;
let indent: number;
let lineStart: boolean;
@@ -3148,15 +3167,14 @@ namespace ts {
(node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent).name === node);
}
- export function isEmptyObjectLiteralOrArrayLiteral(expression: Node): boolean {
- const kind = expression.kind;
- if (kind === SyntaxKind.ObjectLiteralExpression) {
- return (expression).properties.length === 0;
- }
- if (kind === SyntaxKind.ArrayLiteralExpression) {
- return (expression).elements.length === 0;
- }
- return false;
+ export function isEmptyObjectLiteral(expression: Node): boolean {
+ return expression.kind === SyntaxKind.ObjectLiteralExpression &&
+ (expression).properties.length === 0;
+ }
+
+ export function isEmptyArrayLiteral(expression: Node): boolean {
+ return expression.kind === SyntaxKind.ArrayLiteralExpression &&
+ (expression).elements.length === 0;
}
export function getLocalSymbolForExportDefault(symbol: Symbol) {
diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts
index 2d75d646128..133c62e1926 100644
--- a/src/compiler/visitor.ts
+++ b/src/compiler/visitor.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
@@ -154,9 +154,9 @@ namespace ts {
* Starts a new lexical environment and visits a parameter list, suspending the lexical
* environment upon completion.
*/
- export function visitParameterList(nodes: NodeArray, visitor: Visitor, context: TransformationContext) {
+ export function visitParameterList(nodes: NodeArray, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes) {
context.startLexicalEnvironment();
- const updated = visitNodes(nodes, visitor, isParameterDeclaration);
+ const updated = nodesVisitor(nodes, visitor, isParameterDeclaration);
context.suspendLexicalEnvironment();
return updated;
}
@@ -204,9 +204,9 @@ namespace ts {
* @param visitor The callback used to visit each child.
* @param context A lexical environment context for the visitor.
*/
- export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext): T | undefined;
+ export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes): T | undefined;
- export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext): Node {
+ export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes): Node {
if (node === undefined) {
return undefined;
}
@@ -243,8 +243,8 @@ namespace ts {
// Signature elements
case SyntaxKind.Parameter:
return updateParameter(node,
- visitNodes((node).decorators, visitor, isDecorator),
- visitNodes((node).modifiers, visitor, isModifier),
+ nodesVisitor((node).decorators, visitor, isDecorator),
+ nodesVisitor((node).modifiers, visitor, isModifier),
(node).dotDotDotToken,
visitNode((node).name, visitor, isBindingName),
visitNode((node).type, visitor, isTypeNode),
@@ -257,55 +257,55 @@ namespace ts {
// Type member
case SyntaxKind.PropertyDeclaration:
return updateProperty(node,
- visitNodes((node).decorators, visitor, isDecorator),
- visitNodes((node).modifiers, visitor, isModifier),
+ nodesVisitor((node).decorators, visitor, isDecorator),
+ nodesVisitor((node).modifiers, visitor, isModifier),
visitNode((node).name, visitor, isPropertyName),
visitNode((node).type, visitor, isTypeNode),
visitNode((node).initializer, visitor, isExpression));
case SyntaxKind.MethodDeclaration:
return updateMethod(node,
- visitNodes((node).decorators, visitor, isDecorator),
- visitNodes((node).modifiers, visitor, isModifier),
+ nodesVisitor((node).decorators, visitor, isDecorator),
+ nodesVisitor((node).modifiers, visitor, isModifier),
(node).asteriskToken,
visitNode((node).name, visitor, isPropertyName),
- visitNodes((node).typeParameters, visitor, isTypeParameter),
- visitParameterList((node).parameters, visitor, context),
+ nodesVisitor((node).typeParameters, visitor, isTypeParameter),
+ visitParameterList((node).parameters, visitor, context, nodesVisitor),
visitNode((node).type, visitor, isTypeNode),
visitFunctionBody((node).body, visitor, context));
case SyntaxKind.Constructor:
return updateConstructor(node,
- visitNodes((node).decorators, visitor, isDecorator),
- visitNodes((node).modifiers, visitor, isModifier),
- visitParameterList((node).parameters, visitor, context),
+ nodesVisitor((node).decorators, visitor, isDecorator),
+ nodesVisitor((node).modifiers, visitor, isModifier),
+ visitParameterList((node).parameters, visitor, context, nodesVisitor),
visitFunctionBody((node).body, visitor, context));
case SyntaxKind.GetAccessor:
return updateGetAccessor(node,
- visitNodes((node).decorators, visitor, isDecorator),
- visitNodes((node).modifiers, visitor, isModifier),
+ nodesVisitor((node).decorators, visitor, isDecorator),
+ nodesVisitor((node).modifiers, visitor, isModifier),
visitNode((node).name, visitor, isPropertyName),
- visitParameterList((node).parameters, visitor, context),
+ visitParameterList((node).parameters, visitor, context, nodesVisitor),
visitNode((node).type, visitor, isTypeNode),
visitFunctionBody((node).body, visitor, context));
case SyntaxKind.SetAccessor:
return updateSetAccessor(node,
- visitNodes((node).decorators, visitor, isDecorator),
- visitNodes((node).modifiers, visitor, isModifier),
+ nodesVisitor((node).decorators, visitor, isDecorator),
+ nodesVisitor((node).modifiers, visitor, isModifier),
visitNode((node).name, visitor, isPropertyName),
- visitParameterList((node).parameters, visitor, context),
+ visitParameterList((node).parameters, visitor, context, nodesVisitor),
visitFunctionBody((node).body, visitor, context));
// Binding patterns
case SyntaxKind.ObjectBindingPattern:
return updateObjectBindingPattern(node,
- visitNodes((node).elements, visitor, isBindingElement));
+ nodesVisitor((node).elements, visitor, isBindingElement));
case SyntaxKind.ArrayBindingPattern:
return updateArrayBindingPattern(node,
- visitNodes((node).elements, visitor, isArrayBindingElement));
+ nodesVisitor((node).elements, visitor, isArrayBindingElement));
case SyntaxKind.BindingElement:
return updateBindingElement(node,
@@ -317,11 +317,11 @@ namespace ts {
// Expression
case SyntaxKind.ArrayLiteralExpression:
return updateArrayLiteral(node,
- visitNodes((node).elements, visitor, isExpression));
+ nodesVisitor((node).elements, visitor, isExpression));
case SyntaxKind.ObjectLiteralExpression:
return updateObjectLiteral(node,
- visitNodes((node).properties, visitor, isObjectLiteralElementLike));
+ nodesVisitor((node).properties, visitor, isObjectLiteralElementLike));
case SyntaxKind.PropertyAccessExpression:
return updatePropertyAccess(node,
@@ -336,14 +336,14 @@ namespace ts {
case SyntaxKind.CallExpression:
return updateCall(node,
visitNode((node).expression, visitor, isExpression),
- visitNodes((node).typeArguments, visitor, isTypeNode),
- visitNodes((node).arguments, visitor, isExpression));
+ nodesVisitor((node).typeArguments, visitor, isTypeNode),
+ nodesVisitor((node).arguments, visitor, isExpression));
case SyntaxKind.NewExpression:
return updateNew(node,
visitNode((node).expression, visitor, isExpression),
- visitNodes((node).typeArguments, visitor, isTypeNode),
- visitNodes((node).arguments, visitor, isExpression));
+ nodesVisitor((node).typeArguments, visitor, isTypeNode),
+ nodesVisitor((node).arguments, visitor, isExpression));
case SyntaxKind.TaggedTemplateExpression:
return updateTaggedTemplate(node,
@@ -361,19 +361,19 @@ namespace ts {
case SyntaxKind.FunctionExpression:
return updateFunctionExpression(node,
- visitNodes((node).modifiers, visitor, isModifier),
+ nodesVisitor((node).modifiers, visitor, isModifier),
(node).asteriskToken,
visitNode((