Skip to content

Commit 5261467

Browse files
committed
Merge branch 'master' of https://github.com/Microsoft/TypeScript into typedefForJsdoc
2 parents 59b188d + 13900aa commit 5261467

File tree

82 files changed

+2217
-575
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2217
-575
lines changed

Jakefile.js

Lines changed: 89 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,9 @@ function cleanTestDirs() {
680680
}
681681

682682
// used to pass data from jake command line directly to run.js
683-
function writeTestConfigFile(tests, light, testConfigFile) {
684-
console.log('Running test(s): ' + tests);
685-
var testConfigContents = JSON.stringify({ test: [tests], light: light });
683+
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, testConfigFile) {
684+
var testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light: light, workerCount: workerCount, taskConfigsFolder: taskConfigsFolder });
685+
console.log('Running tests with config: ' + testConfigContents);
686686
fs.writeFileSync('test.config', testConfigContents);
687687
}
688688

@@ -692,7 +692,7 @@ function deleteTemporaryProjectOutput() {
692692
}
693693
}
694694

695-
function runConsoleTests(defaultReporter, defaultSubsets) {
695+
function runConsoleTests(defaultReporter, runInParallel) {
696696
cleanTestDirs();
697697
var debug = process.env.debug || process.env.d;
698698
tests = process.env.test || process.env.tests || process.env.t;
@@ -701,9 +701,22 @@ function runConsoleTests(defaultReporter, defaultSubsets) {
701701
if(fs.existsSync(testConfigFile)) {
702702
fs.unlinkSync(testConfigFile);
703703
}
704+
var workerCount, taskConfigsFolder;
705+
if (runInParallel) {
706+
// generate name to store task configuration files
707+
var prefix = os.tmpdir() + "/ts-tests";
708+
var i = 1;
709+
do {
710+
taskConfigsFolder = prefix + i;
711+
i++;
712+
} while (fs.existsSync(taskConfigsFolder));
713+
fs.mkdirSync(taskConfigsFolder);
714+
715+
workerCount = process.env.workerCount || os.cpus().length;
716+
}
704717

705-
if (tests || light) {
706-
writeTestConfigFile(tests, light, testConfigFile);
718+
if (tests || light || taskConfigsFolder) {
719+
writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, testConfigFile);
707720
}
708721

709722
if (tests && tests.toLocaleLowerCase() === "rwc") {
@@ -717,61 +730,93 @@ function runConsoleTests(defaultReporter, defaultSubsets) {
717730

718731
// timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally
719732
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
720-
var subsetRegexes;
721-
if(defaultSubsets.length === 0) {
722-
subsetRegexes = [tests];
733+
if(!runInParallel) {
734+
tests = tests ? ' -g "' + tests + '"' : '';
735+
var cmd = "mocha" + (debug ? " --debug-brk" : "") + " -R " + reporter + tests + colors + ' -t ' + testTimeout + ' ' + run;
736+
console.log(cmd);
737+
exec(cmd, function () {
738+
runLinter();
739+
finish();
740+
}, function(e, status) {
741+
finish(status);
742+
});
743+
723744
}
724745
else {
725-
var subsets = tests ? tests.split("|") : defaultSubsets;
726-
subsetRegexes = subsets.map(function (sub) { return "^" + sub + ".*$"; });
727-
subsetRegexes.push("^(?!" + subsets.join("|") + ").*$");
728-
}
729-
var counter = subsetRegexes.length;
730-
var errorStatus;
731-
subsetRegexes.forEach(function (subsetRegex, i) {
732-
tests = subsetRegex ? ' -g "' + subsetRegex + '"' : '';
733-
var cmd = "mocha" + (debug ? " --debug-brk" : "") + " -R " + reporter + tests + colors + ' -t ' + testTimeout + ' ' + run;
746+
// run task to load all tests and partition them between workers
747+
var cmd = "mocha " + " -R min " + colors + run;
734748
console.log(cmd);
735-
function finish(status) {
736-
counter--;
737-
// save first error status
738-
if (status !== undefined && errorStatus === undefined) {
739-
errorStatus = status;
740-
}
741-
742-
deleteTemporaryProjectOutput();
743-
if (counter !== 0 || errorStatus === undefined) {
744-
// run linter when last worker is finished
745-
if (lintFlag && counter === 0) {
746-
var lint = jake.Task['lint'];
747-
lint.addListener('complete', function () {
749+
exec(cmd, function() {
750+
// read all configuration files and spawn a worker for every config
751+
var configFiles = fs.readdirSync(taskConfigsFolder);
752+
var counter = configFiles.length;
753+
var firstErrorStatus;
754+
// schedule work for chunks
755+
configFiles.forEach(function (f) {
756+
var configPath = path.join(taskConfigsFolder, f);
757+
var workerCmd = "mocha" + " -t " + testTimeout + " -R " + reporter + " " + colors + " " + run + " --config='" + configPath + "'";
758+
console.log(workerCmd);
759+
exec(workerCmd, finishWorker, finishWorker)
760+
});
761+
762+
function finishWorker(e, errorStatus) {
763+
counter--;
764+
if (firstErrorStatus === undefined && errorStatus !== undefined) {
765+
firstErrorStatus = errorStatus;
766+
}
767+
if (counter !== 0) {
768+
complete();
769+
}
770+
else {
771+
// last worker clean everything and runs linter in case if there were no errors
772+
deleteTemporaryProjectOutput();
773+
jake.rmRf(taskConfigsFolder);
774+
if (firstErrorStatus === undefined) {
775+
runLinter();
748776
complete();
749-
});
750-
lint.invoke();
777+
}
778+
else {
779+
failWithStatus(firstErrorStatus);
780+
}
751781
}
752-
complete();
753-
}
754-
else {
755-
fail("Process exited with code " + status);
756782
}
783+
});
784+
}
785+
786+
function failWithStatus(status) {
787+
fail("Process exited with code " + status);
788+
}
789+
790+
function finish(errorStatus) {
791+
deleteTemporaryProjectOutput();
792+
if (errorStatus !== undefined) {
793+
failWithStatus(errorStatus);
757794
}
758-
exec(cmd, function () {
759-
finish();
760-
}, function(e, status) {
761-
finish(status);
795+
else {
796+
complete();
797+
}
798+
}
799+
function runLinter() {
800+
if (!lintFlag) {
801+
return;
802+
}
803+
var lint = jake.Task['lint'];
804+
lint.addListener('complete', function () {
805+
complete();
762806
});
763-
});
807+
lint.invoke();
808+
}
764809
}
765810

766811
var testTimeout = 20000;
767812
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
768813
task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function() {
769-
runConsoleTests('min', ['compiler', 'conformance', 'Projects', 'fourslash']);
814+
runConsoleTests('min', /*runInParallel*/ true);
770815
}, {async: true});
771816

772817
desc("Runs the tests using the built run.js file. Optional arguments are: t[ests]=regex r[eporter]=[list|spec|json|<more>] d[ebug]=true color[s]=false lint=true.");
773818
task("runtests", ["build-rules", "tests", builtLocalDirectory], function() {
774-
runConsoleTests('mocha-fivemat-progress-reporter', []);
819+
runConsoleTests('mocha-fivemat-progress-reporter', /*runInParallel*/ false);
775820
}, {async: true});
776821

777822
desc("Generates code coverage data via instanbul");

src/compiler/binder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,8 +929,8 @@ namespace ts {
929929
preSwitchCaseFlow = currentFlow;
930930
bind(node.caseBlock);
931931
addAntecedent(postSwitchLabel, currentFlow);
932-
const hasDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause);
933-
if (!hasDefault) {
932+
const hasNonEmptyDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause && c.statements.length);
933+
if (!hasNonEmptyDefault) {
934934
addAntecedent(postSwitchLabel, preSwitchCaseFlow);
935935
}
936936
currentBreakTarget = saveBreakTarget;

src/compiler/checker.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,11 +1180,7 @@ namespace ts {
11801180
}
11811181

11821182
// This function is only for imports with entity names
1183-
function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, importDeclaration?: ImportEqualsDeclaration): Symbol {
1184-
if (!importDeclaration) {
1185-
importDeclaration = <ImportEqualsDeclaration>getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration);
1186-
Debug.assert(importDeclaration !== undefined);
1187-
}
1183+
function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, importDeclaration: ImportEqualsDeclaration, dontResolveAlias?: boolean): Symbol {
11881184
// There are three things we might try to look for. In the following examples,
11891185
// the search term is enclosed in |...|:
11901186
//
@@ -1196,13 +1192,13 @@ namespace ts {
11961192
}
11971193
// Check for case 1 and 3 in the above example
11981194
if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) {
1199-
return resolveEntityName(entityName, SymbolFlags.Namespace);
1195+
return resolveEntityName(entityName, SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
12001196
}
12011197
else {
12021198
// Case 2 in above example
12031199
// entityName.kind could be a QualifiedName or a Missing identifier
12041200
Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration);
1205-
return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
1201+
return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
12061202
}
12071203
}
12081204

@@ -1211,7 +1207,7 @@ namespace ts {
12111207
}
12121208

12131209
// Resolves a qualified name and any involved aliases
1214-
function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags, ignoreErrors?: boolean): Symbol {
1210+
function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean): Symbol {
12151211
if (nodeIsMissing(name)) {
12161212
return undefined;
12171213
}
@@ -1245,7 +1241,7 @@ namespace ts {
12451241
Debug.fail("Unknown entity name kind.");
12461242
}
12471243
Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
1248-
return symbol.flags & meaning ? symbol : resolveAlias(symbol);
1244+
return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol);
12491245
}
12501246

12511247
function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression): Symbol {
@@ -9970,9 +9966,9 @@ namespace ts {
99709966
}
99719967

99729968
const apparentType = getApparentType(getWidenedType(type));
9973-
if (apparentType === unknownType) {
9974-
// handle cases when type is Type parameter with invalid constraint
9975-
return unknownType;
9969+
if (apparentType === unknownType || (type.flags & TypeFlags.TypeParameter && isTypeAny(apparentType))) {
9970+
// handle cases when type is Type parameter with invalid or any constraint
9971+
return apparentType;
99769972
}
99779973
const prop = getPropertyOfType(apparentType, right.text);
99789974
if (!prop) {
@@ -11163,7 +11159,9 @@ namespace ts {
1116311159
// types are provided for the argument expressions, and the result is always of type Any.
1116411160
// We exclude union types because we may have a union of function types that happen to have
1116511161
// no common signatures.
11166-
if (isTypeAny(funcType) || (!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
11162+
if (isTypeAny(funcType) ||
11163+
(isTypeAny(apparentType) && funcType.flags & TypeFlags.TypeParameter) ||
11164+
(!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
1116711165
// The unknownType indicates that an error already occurred (and was reported). No
1116811166
// need to report another error in this case.
1116911167
if (funcType !== unknownType && node.typeArguments) {
@@ -14543,6 +14541,12 @@ namespace ts {
1454314541
}
1454414542

1454514543
function areDeclarationFlagsIdentical(left: Declaration, right: Declaration) {
14544+
if ((left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) ||
14545+
(left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter)) {
14546+
// Differences in optionality between parameters and variables are allowed.
14547+
return true;
14548+
}
14549+
1454614550
if (hasQuestionToken(left) !== hasQuestionToken(right)) {
1454714551
return false;
1454814552
}
@@ -16810,7 +16814,9 @@ namespace ts {
1681016814
if (entityName.kind !== SyntaxKind.PropertyAccessExpression) {
1681116815
if (isInRightSideOfImportOrExportAssignment(<EntityName>entityName)) {
1681216816
// Since we already checked for ExportAssignment, this really could only be an Import
16813-
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>entityName);
16817+
const importEqualsDeclaration = <ImportEqualsDeclaration>getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration);
16818+
Debug.assert(importEqualsDeclaration !== undefined);
16819+
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>entityName, importEqualsDeclaration, /*dontResolveAlias*/ true);
1681416820
}
1681516821
}
1681616822

@@ -16906,9 +16912,7 @@ namespace ts {
1690616912

1690716913
if (node.kind === SyntaxKind.Identifier) {
1690816914
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
16909-
return node.parent.kind === SyntaxKind.ExportAssignment
16910-
? getSymbolOfEntityNameOrPropertyAccessExpression(<Identifier>node)
16911-
: getSymbolOfPartOfRightHandSideOfImportEquals(<Identifier>node);
16915+
return getSymbolOfEntityNameOrPropertyAccessExpression(<Identifier>node);
1691216916
}
1691316917
else if (node.parent.kind === SyntaxKind.BindingElement &&
1691416918
node.parent.parent.kind === SyntaxKind.ObjectBindingPattern &&

src/harness/compilerRunner.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const enum CompilerTestType {
1212

1313
class CompilerBaselineRunner extends RunnerBase {
1414
private basePath = "tests/cases";
15-
private testSuiteName: string;
15+
private testSuiteName: TestRunnerKind;
1616
private errors: boolean;
1717
private emit: boolean;
1818
private decl: boolean;
@@ -41,6 +41,14 @@ class CompilerBaselineRunner extends RunnerBase {
4141
this.basePath += "/" + this.testSuiteName;
4242
}
4343

44+
public kind() {
45+
return this.testSuiteName;
46+
}
47+
48+
public enumerateTestFiles() {
49+
return this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true });
50+
}
51+
4452
private makeUnitName(name: string, root: string) {
4553
return ts.isRootedDiskPath(name) ? name : ts.combinePaths(root, name);
4654
};
@@ -391,7 +399,7 @@ class CompilerBaselineRunner extends RunnerBase {
391399

392400
// this will set up a series of describe/it blocks to run between the setup and cleanup phases
393401
if (this.tests.length === 0) {
394-
const testFiles = this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true });
402+
const testFiles = this.enumerateTestFiles();
395403
testFiles.forEach(fn => {
396404
fn = fn.replace(/\\/g, "/");
397405
this.checkTestCodeOutput(fn);

0 commit comments

Comments
 (0)