Skip to content

Commit f96980d

Browse files
committed
merge with master
2 parents f9eaed7 + 9afc2b3 commit f96980d

31 files changed

+412
-139
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4948,34 +4948,34 @@ namespace ts {
49484948
resolved.stringIndexType || resolved.numberIndexType || getPropertyOfType(type, name)) {
49494949
return true;
49504950
}
4951-
return false;
49524951
}
4953-
if (type.flags & TypeFlags.UnionOrIntersection) {
4952+
else if (type.flags & TypeFlags.UnionOrIntersection) {
49544953
for (let t of (<UnionOrIntersectionType>type).types) {
49554954
if (isKnownProperty(t, name)) {
49564955
return true;
49574956
}
49584957
}
4959-
return false;
49604958
}
4961-
return true;
4959+
return false;
49624960
}
49634961

49644962
function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean {
4965-
for (let prop of getPropertiesOfObjectType(source)) {
4966-
if (!isKnownProperty(target, prop.name)) {
4967-
if (reportErrors) {
4968-
// We know *exactly* where things went wrong when comparing the types.
4969-
// Use this property as the error node as this will be more helpful in
4970-
// reasoning about what went wrong.
4971-
errorNode = prop.valueDeclaration;
4972-
reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
4973-
symbolToString(prop),
4974-
typeToString(target));
4963+
if (someConstituentTypeHasKind(target, TypeFlags.ObjectType)) {
4964+
for (let prop of getPropertiesOfObjectType(source)) {
4965+
if (!isKnownProperty(target, prop.name)) {
4966+
if (reportErrors) {
4967+
// We know *exactly* where things went wrong when comparing the types.
4968+
// Use this property as the error node as this will be more helpful in
4969+
// reasoning about what went wrong.
4970+
errorNode = prop.valueDeclaration;
4971+
reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
4972+
symbolToString(prop), typeToString(target));
4973+
}
4974+
return true;
49754975
}
4976-
return true;
49774976
}
49784977
}
4978+
return false;
49794979
}
49804980

49814981
function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary {
@@ -7524,9 +7524,6 @@ namespace ts {
75247524
case SyntaxKind.JsxSelfClosingElement:
75257525
checkJsxSelfClosingElement(<JsxSelfClosingElement>child);
75267526
break;
7527-
default:
7528-
// No checks for JSX Text
7529-
Debug.assert(child.kind === SyntaxKind.JsxText);
75307527
}
75317528
}
75327529

src/compiler/core.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,7 @@ namespace ts {
775775
};
776776

777777
export interface ObjectAllocator {
778-
getNodeConstructor(kind: SyntaxKind): new () => Node;
778+
getNodeConstructor(kind: SyntaxKind): new (pos?: number, end?: number) => Node;
779779
getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol;
780780
getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type;
781781
getSignatureConstructor(): new (checker: TypeChecker) => Signature;
@@ -796,15 +796,13 @@ namespace ts {
796796

797797
export let objectAllocator: ObjectAllocator = {
798798
getNodeConstructor: kind => {
799-
function Node() {
799+
function Node(pos: number, end: number) {
800+
this.pos = pos;
801+
this.end = end;
802+
this.flags = NodeFlags.None;
803+
this.parent = undefined;
800804
}
801-
Node.prototype = {
802-
kind: kind,
803-
pos: -1,
804-
end: -1,
805-
flags: 0,
806-
parent: undefined,
807-
};
805+
Node.prototype = { kind };
808806
return <any>Node;
809807
},
810808
getSymbolConstructor: () => <any>Symbol,
@@ -844,9 +842,9 @@ namespace ts {
844842

845843
export function copyListRemovingItem<T>(item: T, list: T[]) {
846844
let copiedList: T[] = [];
847-
for (var i = 0, len = list.length; i < len; i++) {
848-
if (list[i] !== item) {
849-
copiedList.push(list[i]);
845+
for (let e of list) {
846+
if (e !== item) {
847+
copiedList.push(e);
850848
}
851849
}
852850
return copiedList;

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,10 @@
17201720
"category": "Error",
17211721
"code": 2656
17221722
},
1723+
"JSX expressions must have one parent element": {
1724+
"category": "Error",
1725+
"code": 2657
1726+
},
17231727
"Import declaration '{0}' is using private name '{1}'.": {
17241728
"category": "Error",
17251729
"code": 4000

src/compiler/emitter.ts

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,34 +1769,39 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
17691769
write(".");
17701770
}
17711771
}
1772-
else if (modulekind !== ModuleKind.ES6) {
1773-
let declaration = resolver.getReferencedImportDeclaration(node);
1774-
if (declaration) {
1775-
if (declaration.kind === SyntaxKind.ImportClause) {
1776-
// Identifier references default import
1777-
write(getGeneratedNameForNode(<ImportDeclaration>declaration.parent));
1778-
write(languageVersion === ScriptTarget.ES3 ? "[\"default\"]" : ".default");
1779-
return;
1780-
}
1781-
else if (declaration.kind === SyntaxKind.ImportSpecifier) {
1782-
// Identifier references named import
1783-
write(getGeneratedNameForNode(<ImportDeclaration>declaration.parent.parent.parent));
1784-
let name = (<ImportSpecifier>declaration).propertyName || (<ImportSpecifier>declaration).name;
1785-
let identifier = getSourceTextOfNodeFromSourceFile(currentSourceFile, name);
1786-
if (languageVersion === ScriptTarget.ES3 && identifier === "default") {
1787-
write(`["default"]`);
1772+
else {
1773+
if (modulekind !== ModuleKind.ES6) {
1774+
let declaration = resolver.getReferencedImportDeclaration(node);
1775+
if (declaration) {
1776+
if (declaration.kind === SyntaxKind.ImportClause) {
1777+
// Identifier references default import
1778+
write(getGeneratedNameForNode(<ImportDeclaration>declaration.parent));
1779+
write(languageVersion === ScriptTarget.ES3 ? "[\"default\"]" : ".default");
1780+
return;
17881781
}
1789-
else {
1790-
write(".");
1791-
write(identifier);
1782+
else if (declaration.kind === SyntaxKind.ImportSpecifier) {
1783+
// Identifier references named import
1784+
write(getGeneratedNameForNode(<ImportDeclaration>declaration.parent.parent.parent));
1785+
let name = (<ImportSpecifier>declaration).propertyName || (<ImportSpecifier>declaration).name;
1786+
let identifier = getSourceTextOfNodeFromSourceFile(currentSourceFile, name);
1787+
if (languageVersion === ScriptTarget.ES3 && identifier === "default") {
1788+
write(`["default"]`);
1789+
}
1790+
else {
1791+
write(".");
1792+
write(identifier);
1793+
}
1794+
return;
17921795
}
1793-
return;
17941796
}
17951797
}
1796-
declaration = resolver.getReferencedNestedRedeclaration(node);
1797-
if (declaration) {
1798-
write(getGeneratedNameForNode(declaration.name));
1799-
return;
1798+
1799+
if (languageVersion !== ScriptTarget.ES6) {
1800+
let declaration = resolver.getReferencedNestedRedeclaration(node);
1801+
if (declaration) {
1802+
write(getGeneratedNameForNode(declaration.name));
1803+
return;
1804+
}
18001805
}
18011806
}
18021807

@@ -2785,7 +2790,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
27852790

27862791
/**
27872792
* Emit ES7 exponentiation operator downlevel using Math.pow
2788-
* @param node a binary expression node containing exponentiationOperator (**, **=)
2793+
* @param node a binary expression node containing exponentiationOperator (**, **=)
27892794
*/
27902795
function emitExponentiationOperator(node: BinaryExpression) {
27912796
let leftHandSideExpression = node.left;

src/compiler/parser.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
/// <reference path="utilities.ts"/>
33

44
namespace ts {
5-
let nodeConstructors = new Array<new () => Node>(SyntaxKind.Count);
5+
let nodeConstructors = new Array<new (pos: number, end: number) => Node>(SyntaxKind.Count);
66
/* @internal */ export let parseTime = 0;
77

8-
export function getNodeConstructor(kind: SyntaxKind): new () => Node {
8+
export function getNodeConstructor(kind: SyntaxKind): new (pos?: number, end?: number) => Node {
99
return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind));
1010
}
1111

12-
export function createNode(kind: SyntaxKind): Node {
13-
return new (getNodeConstructor(kind))();
12+
export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node {
13+
return new (getNodeConstructor(kind))(pos, end);
1414
}
1515

1616
function visitNode<T>(cbNode: (node: Node) => T, node: Node): T {
@@ -993,14 +993,10 @@ namespace ts {
993993

994994
function createNode(kind: SyntaxKind, pos?: number): Node {
995995
nodeCount++;
996-
let node = new (nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)))();
997996
if (!(pos >= 0)) {
998997
pos = scanner.getStartPos();
999998
}
1000-
1001-
node.pos = pos;
1002-
node.end = pos;
1003-
return node;
999+
return new (nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)))(pos, pos);
10041000
}
10051001

10061002
function finishNode<T extends Node>(node: T, end?: number): T {
@@ -3454,19 +3450,43 @@ namespace ts {
34543450

34553451
function parseJsxElementOrSelfClosingElement(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement {
34563452
let opening = parseJsxOpeningOrSelfClosingElement(inExpressionContext);
3453+
let result: JsxElement | JsxSelfClosingElement;
34573454
if (opening.kind === SyntaxKind.JsxOpeningElement) {
34583455
let node = <JsxElement>createNode(SyntaxKind.JsxElement, opening.pos);
34593456
node.openingElement = opening;
34603457

34613458
node.children = parseJsxChildren(node.openingElement.tagName);
34623459
node.closingElement = parseJsxClosingElement(inExpressionContext);
3463-
return finishNode(node);
3460+
result = finishNode(node);
34643461
}
34653462
else {
34663463
Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement);
34673464
// Nothing else to do for self-closing elements
3468-
return <JsxSelfClosingElement>opening;
3465+
result = <JsxSelfClosingElement>opening;
3466+
}
3467+
3468+
// If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in
3469+
// an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag
3470+
// as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX
3471+
// element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter
3472+
// does less damage and we can report a better error.
3473+
// Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios
3474+
// of one sort or another.
3475+
if (inExpressionContext && token === SyntaxKind.LessThanToken) {
3476+
let invalidElement = tryParse(() => parseJsxElementOrSelfClosingElement(/*inExpressionContext*/true));
3477+
if (invalidElement) {
3478+
parseErrorAtCurrentToken(Diagnostics.JSX_expressions_must_have_one_parent_element);
3479+
let badNode = <BinaryExpression>createNode(SyntaxKind.BinaryExpression, result.pos);
3480+
badNode.end = invalidElement.end;
3481+
badNode.left = result;
3482+
badNode.right = invalidElement;
3483+
badNode.operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false, /*diagnosticMessage*/ undefined);
3484+
badNode.operatorToken.pos = badNode.operatorToken.end = badNode.right.pos;
3485+
return <JsxElement><Node>badNode;
3486+
}
34693487
}
3488+
3489+
return result;
34703490
}
34713491

34723492
function parseJsxText(): JsxText {

src/compiler/sys.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ namespace ts {
407407
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
408408
return _fs.watch(
409409
path,
410-
{ persisten: true, recursive: !!recursive },
410+
{ persistent: true, recursive: !!recursive },
411411
(eventName: string, relativeFileName: string) => {
412412
// In watchDirectory we only care about adding and removing files (when event name is
413413
// "rename"); changes made within files are handled by corresponding fileWatchers (when

src/compiler/tsc.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,8 @@ namespace ts {
360360
let newFileNames = ts.map(parsedCommandLine.fileNames, compilerHost.getCanonicalFileName);
361361
let canonicalRootFileNames = ts.map(rootFileNames, compilerHost.getCanonicalFileName);
362362

363-
if (!arrayStructurallyIsEqualTo(newFileNames, canonicalRootFileNames)) {
363+
// We check if the project file list has changed. If so, we just throw away the old program and start fresh.
364+
if (!arrayIsEqualTo(newFileNames && newFileNames.sort(), canonicalRootFileNames && canonicalRootFileNames.sort())) {
364365
setCachedProgram(undefined);
365366
startTimerForRecompilation();
366367
}

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ namespace ts {
361361
}
362362

363363
export const enum NodeFlags {
364+
None = 0,
364365
Export = 1 << 1, // Declarations
365366
Ambient = 1 << 2, // Declarations
366367
Public = 1 << 3, // Property/Method
@@ -381,7 +382,6 @@ namespace ts {
381382
ContainsThis = 1 << 18, // Interface contains references to "this"
382383
HasImplicitReturn = 1 << 19, // If function implicitly returns on one of codepaths (initialized by binding)
383384
HasExplicitReturn = 1 << 20, // If function has explicit reachable return on one of codepaths (initialized by binding)
384-
385385
Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async,
386386
AccessibilityModifier = Public | Private | Protected,
387387
BlockScoped = Let | Const,

src/compiler/utilities.ts

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,17 @@ namespace ts {
8282
return node.end - node.pos;
8383
}
8484

85-
export function arrayIsEqualTo<T>(arr1: T[], arr2: T[], comparer?: (a: T, b: T) => boolean): boolean {
86-
if (!arr1 || !arr2) {
87-
return arr1 === arr2;
85+
export function arrayIsEqualTo<T>(array1: T[], array2: T[], equaler?: (a: T, b: T) => boolean): boolean {
86+
if (!array1 || !array2) {
87+
return array1 === array2;
8888
}
8989

90-
if (arr1.length !== arr2.length) {
90+
if (array1.length !== array2.length) {
9191
return false;
9292
}
9393

94-
for (let i = 0; i < arr1.length; ++i) {
95-
let equals = comparer ? comparer(arr1[i], arr2[i]) : arr1[i] === arr2[i];
94+
for (let i = 0; i < array1.length; ++i) {
95+
let equals = equaler ? equaler(array1[i], array2[i]) : array1[i] === array2[i];
9696
if (!equals) {
9797
return false;
9898
}
@@ -1505,7 +1505,7 @@ namespace ts {
15051505
}
15061506

15071507
export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node {
1508-
let node = <SynthesizedNode>createNode(kind);
1508+
let node = <SynthesizedNode>createNode(kind, /* pos */ -1, /* end */ -1);
15091509
node.startsOnNewLine = startsOnNewLine;
15101510
return node;
15111511
}
@@ -2414,16 +2414,4 @@ namespace ts {
24142414
}
24152415
}
24162416
}
2417-
2418-
export function arrayStructurallyIsEqualTo<T>(array1: Array<T>, array2: Array<T>): boolean {
2419-
if (!array1 || !array2) {
2420-
return false;
2421-
}
2422-
2423-
if (array1.length !== array2.length) {
2424-
return false;
2425-
}
2426-
2427-
return arrayIsEqualTo(array1.sort(), array2.sort());
2428-
}
24292417
}

src/harness/harness.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,9 @@ namespace Utils {
274274

275275
case "flags":
276276
// Print out flags with their enum names.
277-
o[propertyName] = getNodeFlagName(n.flags);
277+
if (n.flags) {
278+
o[propertyName] = getNodeFlagName(n.flags);
279+
}
278280
break;
279281

280282
case "parserContextFlags":

src/server/editorServices.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ namespace ts.server {
576576
let newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f)));
577577
let currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f)));
578578

579-
if (!arrayStructurallyIsEqualTo(currentRootFiles, newRootFiles)) {
579+
// We check if the project file list has changed. If so, we update the project.
580+
if (!arrayIsEqualTo(currentRootFiles && currentRootFiles.sort(), newRootFiles && newRootFiles.sort())) {
580581
// For configured projects, the change is made outside the tsconfig file, and
581582
// it is not likely to affect the project for other files opened by the client. We can
582583
// just update the current project.

0 commit comments

Comments
 (0)