From dfee3de3a664d2925110b919e3f3d0b780732fe4 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 21 Apr 2016 10:57:54 -0700 Subject: [PATCH 01/50] Add test case for #8229 --- ...tAnyDestructuringVarDeclaration.errors.txt | 18 ++++-- ...oImplicitAnyDestructuringVarDeclaration.js | 4 +- ...AnyDestructuringVarDeclaration2.errors.txt | 63 +++++++++++++++++++ ...ImplicitAnyDestructuringVarDeclaration2.js | 25 ++++++++ ...oImplicitAnyDestructuringVarDeclaration.ts | 2 +- ...ImplicitAnyDestructuringVarDeclaration2.ts | 12 ++++ 6 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt create mode 100644 tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.js create mode 100644 tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt index 10d6b05c62..e54261b117 100644 --- a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt @@ -15,11 +15,13 @@ tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(5,18): error TS tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(7,5): error TS1182: A destructuring declaration must have an initializer. tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(7,13): error TS7008: Member 'b3' implicitly has an 'any' type. tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(7,25): error TS7008: Member 'b3' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,6): error TS7031: Binding element 'a1' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,26): error TS7031: Binding element 'b1' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,6): error TS7031: Binding element 'a4' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,26): error TS7031: Binding element 'b4' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,46): error TS7005: Variable 'c4' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,62): error TS7005: Variable 'd4' implicitly has an 'any' type. -==== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts (19 errors) ==== +==== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts (21 errors) ==== var [a], {b}, c, d; // error ~~~ !!! error TS1182: A destructuring declaration must have an initializer. @@ -62,8 +64,12 @@ tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,26): error TS ~~ !!! error TS7008: Member 'b3' implicitly has an 'any' type. - var [a1] = [undefined], {b1} = { b1: null }, c1 = undefined, d1 = null; // error + var [a4] = [undefined], {b4} = { b4: null }, c4 = undefined, d4 = null; // error ~~ -!!! error TS7031: Binding element 'a1' implicitly has an 'any' type. +!!! error TS7031: Binding element 'a4' implicitly has an 'any' type. ~~ -!!! error TS7031: Binding element 'b1' implicitly has an 'any' type. \ No newline at end of file +!!! error TS7031: Binding element 'b4' implicitly has an 'any' type. + ~~ +!!! error TS7005: Variable 'c4' implicitly has an 'any' type. + ~~ +!!! error TS7005: Variable 'd4' implicitly has an 'any' type. \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js index cbc15c01e9..4e9606d9c5 100644 --- a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js @@ -7,11 +7,11 @@ var [a2]: [any], {b2}: { b2: any }, c2: any, d2: any; var {b3}: { b3 }, c3: { b3 }; // error in type instead -var [a1] = [undefined], {b1} = { b1: null }, c1 = undefined, d1 = null; // error +var [a4] = [undefined], {b4} = { b4: null }, c4 = undefined, d4 = null; // error //// [noImplicitAnyDestructuringVarDeclaration.js] var a = (void 0)[0], b = (void 0).b, c, d; // error var _a = (void 0)[0], a1 = _a === void 0 ? undefined : _a, _b = (void 0).b1, b1 = _b === void 0 ? null : _b, c1 = undefined, d1 = null; // error var a2 = (void 0)[0], b2 = (void 0).b2, c2, d2; var b3 = (void 0).b3, c3; // error in type instead -var a1 = [undefined][0], b1 = { b1: null }.b1, c1 = undefined, d1 = null; // error +var a4 = [undefined][0], b4 = { b4: null }.b4, c4 = undefined, d4 = null; // error diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt new file mode 100644 index 0000000000..d84a297566 --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt @@ -0,0 +1,63 @@ +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(1,6): error TS7031: Binding element 'a' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(1,9): error TS7031: Binding element 'b' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(1,12): error TS7031: Binding element 'c' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(3,6): error TS7031: Binding element 'a2' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(3,22): error TS7031: Binding element 'b2' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(3,38): error TS7031: Binding element 'c2' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(5,6): error TS7031: Binding element 'a4' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(5,31): error TS7031: Binding element 'b4' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(7,6): error TS7031: Binding element 'x' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(7,9): error TS7031: Binding element 'y' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(7,12): error TS7031: Binding element 'z' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(9,6): error TS7031: Binding element 'x2' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(9,22): error TS7031: Binding element 'y2' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(9,38): error TS7031: Binding element 'z2' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(11,6): error TS7031: Binding element 'x4' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(11,37): error TS7031: Binding element 'y4' implicitly has an 'any' type. + + +==== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts (16 errors) ==== + let [a, b, c] = [1, 2, 3]; // no error + ~ +!!! error TS7031: Binding element 'a' implicitly has an 'any' type. + ~ +!!! error TS7031: Binding element 'b' implicitly has an 'any' type. + ~ +!!! error TS7031: Binding element 'c' implicitly has an 'any' type. + let [a1 = 10, b1 = 10, c1 = 10] = [1, 2, 3]; // no error + let [a2 = undefined, b2 = undefined, c2 = undefined] = [1, 2, 3]; // no error + ~~ +!!! error TS7031: Binding element 'a2' implicitly has an 'any' type. + ~~ +!!! error TS7031: Binding element 'b2' implicitly has an 'any' type. + ~~ +!!! error TS7031: Binding element 'c2' implicitly has an 'any' type. + let [a3 = undefined, b3 = null, c3 = undefined] = [1, 2, 3]; // no error + let [a4] = [undefined], [b4] = [null], c4 = undefined, d4 = null; // no error + ~~ +!!! error TS7031: Binding element 'a4' implicitly has an 'any' type. + ~~ +!!! error TS7031: Binding element 'b4' implicitly has an 'any' type. + + let {x, y, z} = { x: 1, y: 2, z: 3 }; // no error + ~ +!!! error TS7031: Binding element 'x' implicitly has an 'any' type. + ~ +!!! error TS7031: Binding element 'y' implicitly has an 'any' type. + ~ +!!! error TS7031: Binding element 'z' implicitly has an 'any' type. + let {x1 = 10, y1 = 10, z1 = 10} = { x1: 1, y1: 2, z1: 3 }; // no error + let {x2 = undefined, y2 = undefined, z2 = undefined} = { x2: 1, y2: 2, z2: 3 }; // no error + ~~ +!!! error TS7031: Binding element 'x2' implicitly has an 'any' type. + ~~ +!!! error TS7031: Binding element 'y2' implicitly has an 'any' type. + ~~ +!!! error TS7031: Binding element 'z2' implicitly has an 'any' type. + let {x3 = undefined, y3 = null, z3 = undefined} = { x3: 1, y3: 2, z3: 3 }; // no error + let {x4} = { x4: undefined }, {y4} = { y4: null }; // no error + ~~ +!!! error TS7031: Binding element 'x4' implicitly has an 'any' type. + ~~ +!!! error TS7031: Binding element 'y4' implicitly has an 'any' type. + \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.js b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.js new file mode 100644 index 0000000000..79ee0b8830 --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.js @@ -0,0 +1,25 @@ +//// [noImplicitAnyDestructuringVarDeclaration2.ts] +let [a, b, c] = [1, 2, 3]; // no error +let [a1 = 10, b1 = 10, c1 = 10] = [1, 2, 3]; // no error +let [a2 = undefined, b2 = undefined, c2 = undefined] = [1, 2, 3]; // no error +let [a3 = undefined, b3 = null, c3 = undefined] = [1, 2, 3]; // no error +let [a4] = [undefined], [b4] = [null], c4 = undefined, d4 = null; // no error + +let {x, y, z} = { x: 1, y: 2, z: 3 }; // no error +let {x1 = 10, y1 = 10, z1 = 10} = { x1: 1, y1: 2, z1: 3 }; // no error +let {x2 = undefined, y2 = undefined, z2 = undefined} = { x2: 1, y2: 2, z2: 3 }; // no error +let {x3 = undefined, y3 = null, z3 = undefined} = { x3: 1, y3: 2, z3: 3 }; // no error +let {x4} = { x4: undefined }, {y4} = { y4: null }; // no error + + +//// [noImplicitAnyDestructuringVarDeclaration2.js] +var _a = [1, 2, 3], a = _a[0], b = _a[1], c = _a[2]; // no error +var _b = [1, 2, 3], _c = _b[0], a1 = _c === void 0 ? 10 : _c, _d = _b[1], b1 = _d === void 0 ? 10 : _d, _e = _b[2], c1 = _e === void 0 ? 10 : _e; // no error +var _f = [1, 2, 3], _g = _f[0], a2 = _g === void 0 ? undefined : _g, _h = _f[1], b2 = _h === void 0 ? undefined : _h, _j = _f[2], c2 = _j === void 0 ? undefined : _j; // no error +var _k = [1, 2, 3], _l = _k[0], a3 = _l === void 0 ? undefined : _l, _m = _k[1], b3 = _m === void 0 ? null : _m, _o = _k[2], c3 = _o === void 0 ? undefined : _o; // no error +var a4 = [undefined][0], b4 = [null][0], c4 = undefined, d4 = null; // no error +var _p = { x: 1, y: 2, z: 3 }, x = _p.x, y = _p.y, z = _p.z; // no error +var _q = { x1: 1, y1: 2, z1: 3 }, _r = _q.x1, x1 = _r === void 0 ? 10 : _r, _s = _q.y1, y1 = _s === void 0 ? 10 : _s, _t = _q.z1, z1 = _t === void 0 ? 10 : _t; // no error +var _u = { x2: 1, y2: 2, z2: 3 }, _v = _u.x2, x2 = _v === void 0 ? undefined : _v, _w = _u.y2, y2 = _w === void 0 ? undefined : _w, _x = _u.z2, z2 = _x === void 0 ? undefined : _x; // no error +var _y = { x3: 1, y3: 2, z3: 3 }, _z = _y.x3, x3 = _z === void 0 ? undefined : _z, _0 = _y.y3, y3 = _0 === void 0 ? null : _0, _1 = _y.z3, z3 = _1 === void 0 ? undefined : _1; // no error +var x4 = { x4: undefined }.x4, y4 = { y4: null }.y4; // no error diff --git a/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts b/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts index 6988416d4d..b9ecd8e72a 100644 --- a/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts +++ b/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts @@ -7,4 +7,4 @@ var [a2]: [any], {b2}: { b2: any }, c2: any, d2: any; var {b3}: { b3 }, c3: { b3 }; // error in type instead -var [a1] = [undefined], {b1} = { b1: null }, c1 = undefined, d1 = null; // error \ No newline at end of file +var [a4] = [undefined], {b4} = { b4: null }, c4 = undefined, d4 = null; // error \ No newline at end of file diff --git a/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts b/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts new file mode 100644 index 0000000000..a964bd96db --- /dev/null +++ b/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts @@ -0,0 +1,12 @@ +// @noimplicitany: true +let [a, b, c] = [1, 2, 3]; // no error +let [a1 = 10, b1 = 10, c1 = 10] = [1, 2, 3]; // no error +let [a2 = undefined, b2 = undefined, c2 = undefined] = [1, 2, 3]; // no error +let [a3 = undefined, b3 = null, c3 = undefined] = [1, 2, 3]; // no error +let [a4] = [undefined], [b4] = [null], c4 = undefined, d4 = null; // no error + +let {x, y, z} = { x: 1, y: 2, z: 3 }; // no error +let {x1 = 10, y1 = 10, z1 = 10} = { x1: 1, y1: 2, z1: 3 }; // no error +let {x2 = undefined, y2 = undefined, z2 = undefined} = { x2: 1, y2: 2, z2: 3 }; // no error +let {x3 = undefined, y3 = null, z3 = undefined} = { x3: 1, y3: 2, z3: 3 }; // no error +let {x4} = { x4: undefined }, {y4} = { y4: null }; // no error From 90d347e855d94bfb24ef644731cc623552a0c854 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 21 Apr 2016 13:25:43 -0700 Subject: [PATCH 02/50] Do not report errors during contextual typecheck Fixes #8229 --- src/compiler/checker.ts | 28 ++-- ...AnyDestructuringVarDeclaration2.errors.txt | 63 -------- ...citAnyDestructuringVarDeclaration2.symbols | 78 ++++++++++ ...licitAnyDestructuringVarDeclaration2.types | 137 ++++++++++++++++++ 4 files changed, 230 insertions(+), 76 deletions(-) delete mode 100644 tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt create mode 100644 tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.symbols create mode 100644 tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 899ee47957..f84988e68b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2873,7 +2873,7 @@ namespace ts { // If the declaration specifies a binding pattern, use the type implied by the binding pattern if (isBindingPattern(declaration.name)) { - return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ false); + return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ false, /*reportErrors*/ true); } // No type specified and nothing can be inferred @@ -2883,23 +2883,25 @@ namespace ts { // Return the type implied by a binding pattern element. This is the type of the initializer of the element if // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding // pattern. Otherwise, it is the type any. - function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean): Type { + function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type { if (element.initializer) { const type = checkExpressionCached(element.initializer); - reportErrorsFromWidening(element, type); + if (reportErrors) { + reportErrorsFromWidening(element, type); + } return getWidenedType(type); } if (isBindingPattern(element.name)) { - return getTypeFromBindingPattern(element.name, includePatternInType); + return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors); } - if (compilerOptions.noImplicitAny && !declarationBelongsToPrivateAmbientMember(element)) { + if (reportErrors && compilerOptions.noImplicitAny && !declarationBelongsToPrivateAmbientMember(element)) { reportImplicitAnyError(element, anyType); } return anyType; } // Return the type implied by an object binding pattern - function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type { + function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { const members: SymbolTable = {}; let hasComputedProperties = false; forEach(pattern.elements, e => { @@ -2913,7 +2915,7 @@ namespace ts { const text = getTextOfPropertyName(name); const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); const symbol = createSymbol(flags, text); - symbol.type = getTypeFromBindingElement(e, includePatternInType); + symbol.type = getTypeFromBindingElement(e, includePatternInType, reportErrors); symbol.bindingElement = e; members[symbol.name] = symbol; }); @@ -2928,13 +2930,13 @@ namespace ts { } // Return the type implied by an array binding pattern - function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type { + function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { const elements = pattern.elements; if (elements.length === 0 || elements[elements.length - 1].dotDotDotToken) { return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType; } // If the pattern has at least one element, and no rest element, then it should imply a tuple type. - const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType)); + const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); if (includePatternInType) { const result = createNewTupleType(elementTypes); result.pattern = pattern; @@ -2950,10 +2952,10 @@ namespace ts { // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of // the parameter. - function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean): Type { + function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean, reportErrors?: boolean): Type { return pattern.kind === SyntaxKind.ObjectBindingPattern - ? getTypeFromObjectBindingPattern(pattern, includePatternInType) - : getTypeFromArrayBindingPattern(pattern, includePatternInType); + ? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors) + : getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors); } // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type @@ -8467,7 +8469,7 @@ namespace ts { } } if (isBindingPattern(declaration.name)) { - return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true); + return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false); } if (isBindingPattern(declaration.parent)) { const parentDeclaration = declaration.parent.parent; diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt deleted file mode 100644 index d84a297566..0000000000 --- a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.errors.txt +++ /dev/null @@ -1,63 +0,0 @@ -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(1,6): error TS7031: Binding element 'a' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(1,9): error TS7031: Binding element 'b' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(1,12): error TS7031: Binding element 'c' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(3,6): error TS7031: Binding element 'a2' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(3,22): error TS7031: Binding element 'b2' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(3,38): error TS7031: Binding element 'c2' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(5,6): error TS7031: Binding element 'a4' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(5,31): error TS7031: Binding element 'b4' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(7,6): error TS7031: Binding element 'x' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(7,9): error TS7031: Binding element 'y' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(7,12): error TS7031: Binding element 'z' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(9,6): error TS7031: Binding element 'x2' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(9,22): error TS7031: Binding element 'y2' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(9,38): error TS7031: Binding element 'z2' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(11,6): error TS7031: Binding element 'x4' implicitly has an 'any' type. -tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts(11,37): error TS7031: Binding element 'y4' implicitly has an 'any' type. - - -==== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts (16 errors) ==== - let [a, b, c] = [1, 2, 3]; // no error - ~ -!!! error TS7031: Binding element 'a' implicitly has an 'any' type. - ~ -!!! error TS7031: Binding element 'b' implicitly has an 'any' type. - ~ -!!! error TS7031: Binding element 'c' implicitly has an 'any' type. - let [a1 = 10, b1 = 10, c1 = 10] = [1, 2, 3]; // no error - let [a2 = undefined, b2 = undefined, c2 = undefined] = [1, 2, 3]; // no error - ~~ -!!! error TS7031: Binding element 'a2' implicitly has an 'any' type. - ~~ -!!! error TS7031: Binding element 'b2' implicitly has an 'any' type. - ~~ -!!! error TS7031: Binding element 'c2' implicitly has an 'any' type. - let [a3 = undefined, b3 = null, c3 = undefined] = [1, 2, 3]; // no error - let [a4] = [undefined], [b4] = [null], c4 = undefined, d4 = null; // no error - ~~ -!!! error TS7031: Binding element 'a4' implicitly has an 'any' type. - ~~ -!!! error TS7031: Binding element 'b4' implicitly has an 'any' type. - - let {x, y, z} = { x: 1, y: 2, z: 3 }; // no error - ~ -!!! error TS7031: Binding element 'x' implicitly has an 'any' type. - ~ -!!! error TS7031: Binding element 'y' implicitly has an 'any' type. - ~ -!!! error TS7031: Binding element 'z' implicitly has an 'any' type. - let {x1 = 10, y1 = 10, z1 = 10} = { x1: 1, y1: 2, z1: 3 }; // no error - let {x2 = undefined, y2 = undefined, z2 = undefined} = { x2: 1, y2: 2, z2: 3 }; // no error - ~~ -!!! error TS7031: Binding element 'x2' implicitly has an 'any' type. - ~~ -!!! error TS7031: Binding element 'y2' implicitly has an 'any' type. - ~~ -!!! error TS7031: Binding element 'z2' implicitly has an 'any' type. - let {x3 = undefined, y3 = null, z3 = undefined} = { x3: 1, y3: 2, z3: 3 }; // no error - let {x4} = { x4: undefined }, {y4} = { y4: null }; // no error - ~~ -!!! error TS7031: Binding element 'x4' implicitly has an 'any' type. - ~~ -!!! error TS7031: Binding element 'y4' implicitly has an 'any' type. - \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.symbols b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.symbols new file mode 100644 index 0000000000..ee7fe9f7ed --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.symbols @@ -0,0 +1,78 @@ +=== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts === +let [a, b, c] = [1, 2, 3]; // no error +>a : Symbol(a, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 0, 5)) +>b : Symbol(b, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 0, 7)) +>c : Symbol(c, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 0, 10)) + +let [a1 = 10, b1 = 10, c1 = 10] = [1, 2, 3]; // no error +>a1 : Symbol(a1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 1, 5)) +>b1 : Symbol(b1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 1, 13)) +>c1 : Symbol(c1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 1, 22)) + +let [a2 = undefined, b2 = undefined, c2 = undefined] = [1, 2, 3]; // no error +>a2 : Symbol(a2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 2, 5)) +>undefined : Symbol(undefined) +>b2 : Symbol(b2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 2, 20)) +>undefined : Symbol(undefined) +>c2 : Symbol(c2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 2, 36)) +>undefined : Symbol(undefined) + +let [a3 = undefined, b3 = null, c3 = undefined] = [1, 2, 3]; // no error +>a3 : Symbol(a3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 3, 5)) +>undefined : Symbol(undefined) +>b3 : Symbol(b3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 3, 25)) +>c3 : Symbol(c3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 3, 41)) +>undefined : Symbol(undefined) + +let [a4] = [undefined], [b4] = [null], c4 = undefined, d4 = null; // no error +>a4 : Symbol(a4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 4, 5)) +>undefined : Symbol(undefined) +>b4 : Symbol(b4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 4, 30)) +>c4 : Symbol(c4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 4, 48)) +>undefined : Symbol(undefined) +>d4 : Symbol(d4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 4, 69)) + +let {x, y, z} = { x: 1, y: 2, z: 3 }; // no error +>x : Symbol(x, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 6, 5)) +>y : Symbol(y, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 6, 7)) +>z : Symbol(z, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 6, 10)) +>x : Symbol(x, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 6, 17)) +>y : Symbol(y, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 6, 23)) +>z : Symbol(z, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 6, 29)) + +let {x1 = 10, y1 = 10, z1 = 10} = { x1: 1, y1: 2, z1: 3 }; // no error +>x1 : Symbol(x1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 7, 5)) +>y1 : Symbol(y1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 7, 13)) +>z1 : Symbol(z1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 7, 22)) +>x1 : Symbol(x1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 7, 35)) +>y1 : Symbol(y1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 7, 42)) +>z1 : Symbol(z1, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 7, 49)) + +let {x2 = undefined, y2 = undefined, z2 = undefined} = { x2: 1, y2: 2, z2: 3 }; // no error +>x2 : Symbol(x2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 8, 5)) +>undefined : Symbol(undefined) +>y2 : Symbol(y2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 8, 20)) +>undefined : Symbol(undefined) +>z2 : Symbol(z2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 8, 36)) +>undefined : Symbol(undefined) +>x2 : Symbol(x2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 8, 56)) +>y2 : Symbol(y2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 8, 63)) +>z2 : Symbol(z2, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 8, 70)) + +let {x3 = undefined, y3 = null, z3 = undefined} = { x3: 1, y3: 2, z3: 3 }; // no error +>x3 : Symbol(x3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 9, 5)) +>undefined : Symbol(undefined) +>y3 : Symbol(y3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 9, 25)) +>z3 : Symbol(z3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 9, 41)) +>undefined : Symbol(undefined) +>x3 : Symbol(x3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 9, 66)) +>y3 : Symbol(y3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 9, 73)) +>z3 : Symbol(z3, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 9, 80)) + +let {x4} = { x4: undefined }, {y4} = { y4: null }; // no error +>x4 : Symbol(x4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 10, 5)) +>x4 : Symbol(x4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 10, 12)) +>undefined : Symbol(undefined) +>y4 : Symbol(y4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 10, 36)) +>y4 : Symbol(y4, Decl(noImplicitAnyDestructuringVarDeclaration2.ts, 10, 43)) + diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.types b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.types new file mode 100644 index 0000000000..ef0a3f2c25 --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration2.types @@ -0,0 +1,137 @@ +=== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration2.ts === +let [a, b, c] = [1, 2, 3]; // no error +>a : number +>b : number +>c : number +>[1, 2, 3] : [number, number, number] +>1 : number +>2 : number +>3 : number + +let [a1 = 10, b1 = 10, c1 = 10] = [1, 2, 3]; // no error +>a1 : number +>10 : number +>b1 : number +>10 : number +>c1 : number +>10 : number +>[1, 2, 3] : [number, number, number] +>1 : number +>2 : number +>3 : number + +let [a2 = undefined, b2 = undefined, c2 = undefined] = [1, 2, 3]; // no error +>a2 : number +>undefined : undefined +>b2 : number +>undefined : undefined +>c2 : number +>undefined : undefined +>[1, 2, 3] : [number, number, number] +>1 : number +>2 : number +>3 : number + +let [a3 = undefined, b3 = null, c3 = undefined] = [1, 2, 3]; // no error +>a3 : number +>undefined : any +>undefined : undefined +>b3 : number +>null : any +>null : null +>c3 : number +>undefined : any +>undefined : undefined +>[1, 2, 3] : [number, number, number] +>1 : number +>2 : number +>3 : number + +let [a4] = [undefined], [b4] = [null], c4 = undefined, d4 = null; // no error +>a4 : any +>[undefined] : [any] +>undefined : any +>undefined : undefined +>b4 : any +>[null] : [any] +>null : any +>null : null +>c4 : any +>undefined : any +>undefined : undefined +>d4 : any +>null : any +>null : null + +let {x, y, z} = { x: 1, y: 2, z: 3 }; // no error +>x : number +>y : number +>z : number +>{ x: 1, y: 2, z: 3 } : { x: number; y: number; z: number; } +>x : number +>1 : number +>y : number +>2 : number +>z : number +>3 : number + +let {x1 = 10, y1 = 10, z1 = 10} = { x1: 1, y1: 2, z1: 3 }; // no error +>x1 : number +>10 : number +>y1 : number +>10 : number +>z1 : number +>10 : number +>{ x1: 1, y1: 2, z1: 3 } : { x1?: number; y1?: number; z1?: number; } +>x1 : number +>1 : number +>y1 : number +>2 : number +>z1 : number +>3 : number + +let {x2 = undefined, y2 = undefined, z2 = undefined} = { x2: 1, y2: 2, z2: 3 }; // no error +>x2 : number +>undefined : undefined +>y2 : number +>undefined : undefined +>z2 : number +>undefined : undefined +>{ x2: 1, y2: 2, z2: 3 } : { x2?: number; y2?: number; z2?: number; } +>x2 : number +>1 : number +>y2 : number +>2 : number +>z2 : number +>3 : number + +let {x3 = undefined, y3 = null, z3 = undefined} = { x3: 1, y3: 2, z3: 3 }; // no error +>x3 : number +>undefined : any +>undefined : undefined +>y3 : number +>null : any +>null : null +>z3 : number +>undefined : any +>undefined : undefined +>{ x3: 1, y3: 2, z3: 3 } : { x3?: number; y3?: number; z3?: number; } +>x3 : number +>1 : number +>y3 : number +>2 : number +>z3 : number +>3 : number + +let {x4} = { x4: undefined }, {y4} = { y4: null }; // no error +>x4 : any +>{ x4: undefined } : { x4: any; } +>x4 : any +>undefined : any +>undefined : undefined +>y4 : any +>{ y4: null } : { y4: any; } +>y4 : any +>null : any +>null : null + From 34f7f2caed8fe1198e095332500c6bb6f34de819 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 22 Apr 2016 10:40:06 -0700 Subject: [PATCH 03/50] Handle the scenario when let [a=undefined]=[] --- src/compiler/checker.ts | 6 +----- .../noImplicitAnyDestructuringVarDeclaration.errors.txt | 9 +++++++-- .../noImplicitAnyDestructuringVarDeclaration.js | 5 ++++- .../compiler/noImplicitAnyDestructuringVarDeclaration.ts | 4 +++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f84988e68b..a6d1680a6e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2885,11 +2885,7 @@ namespace ts { // pattern. Otherwise, it is the type any. function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type { if (element.initializer) { - const type = checkExpressionCached(element.initializer); - if (reportErrors) { - reportErrorsFromWidening(element, type); - } - return getWidenedType(type); + return checkExpressionCached(element.initializer); } if (isBindingPattern(element.name)) { return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors); diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt index e54261b117..f7e6475b97 100644 --- a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.errors.txt @@ -19,9 +19,10 @@ tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,6): error TS7 tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,26): error TS7031: Binding element 'b4' implicitly has an 'any' type. tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,46): error TS7005: Variable 'c4' implicitly has an 'any' type. tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,62): error TS7005: Variable 'd4' implicitly has an 'any' type. +tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(11,6): error TS7031: Binding element 'a5' implicitly has an 'any' type. -==== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts (21 errors) ==== +==== tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts (22 errors) ==== var [a], {b}, c, d; // error ~~~ !!! error TS1182: A destructuring declaration must have an initializer. @@ -72,4 +73,8 @@ tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts(9,62): error TS ~~ !!! error TS7005: Variable 'c4' implicitly has an 'any' type. ~~ -!!! error TS7005: Variable 'd4' implicitly has an 'any' type. \ No newline at end of file +!!! error TS7005: Variable 'd4' implicitly has an 'any' type. + + var [a5 = undefined] = []; // error + ~~ +!!! error TS7031: Binding element 'a5' implicitly has an 'any' type. \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js index 4e9606d9c5..85358df666 100644 --- a/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js +++ b/tests/baselines/reference/noImplicitAnyDestructuringVarDeclaration.js @@ -7,7 +7,9 @@ var [a2]: [any], {b2}: { b2: any }, c2: any, d2: any; var {b3}: { b3 }, c3: { b3 }; // error in type instead -var [a4] = [undefined], {b4} = { b4: null }, c4 = undefined, d4 = null; // error +var [a4] = [undefined], {b4} = { b4: null }, c4 = undefined, d4 = null; // error + +var [a5 = undefined] = []; // error //// [noImplicitAnyDestructuringVarDeclaration.js] var a = (void 0)[0], b = (void 0).b, c, d; // error @@ -15,3 +17,4 @@ var _a = (void 0)[0], a1 = _a === void 0 ? undefined : _a, _b = (void 0).b1, b1 var a2 = (void 0)[0], b2 = (void 0).b2, c2, d2; var b3 = (void 0).b3, c3; // error in type instead var a4 = [undefined][0], b4 = { b4: null }.b4, c4 = undefined, d4 = null; // error +var _c = [][0], a5 = _c === void 0 ? undefined : _c; // error diff --git a/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts b/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts index b9ecd8e72a..ea99d03bd7 100644 --- a/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts +++ b/tests/cases/compiler/noImplicitAnyDestructuringVarDeclaration.ts @@ -7,4 +7,6 @@ var [a2]: [any], {b2}: { b2: any }, c2: any, d2: any; var {b3}: { b3 }, c3: { b3 }; // error in type instead -var [a4] = [undefined], {b4} = { b4: null }, c4 = undefined, d4 = null; // error \ No newline at end of file +var [a4] = [undefined], {b4} = { b4: null }, c4 = undefined, d4 = null; // error + +var [a5 = undefined] = []; // error \ No newline at end of file From ad56220c4562085b0d638d731269a7b327aeffa8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 14 Jul 2016 14:17:50 -0700 Subject: [PATCH 04/50] Instantiate contextual this parameters if needed --- src/compiler/checker.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aea8c982a9..08ee6bf4b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4632,6 +4632,9 @@ namespace ts { function getThisTypeOfSignature(signature: Signature): Type | undefined { if (signature.thisParameter) { + if (signature.mapper) { + signature = instantiateSignature(signature, signature.mapper); + } return getTypeOfSymbol(signature.thisParameter); } } @@ -11770,6 +11773,10 @@ namespace ts { function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) { const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0); + if (context.thisParameter) { + // save the mapper in case we need to type `this` later + context.mapper = mapper; + } for (let i = 0; i < len; i++) { const parameter = signature.parameters[i]; const contextualParameterType = getTypeAtPosition(context, i); From 78f807c7729f2c3cf092b539a597c58824f45d2a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 14 Jul 2016 14:26:10 -0700 Subject: [PATCH 05/50] Test that contextually typed generic this parameters are instantiated --- ...instantiateContextuallyTypedGenericThis.js | 20 +++++++ ...ntiateContextuallyTypedGenericThis.symbols | 44 ++++++++++++++++ ...tantiateContextuallyTypedGenericThis.types | 52 +++++++++++++++++++ ...instantiateContextuallyTypedGenericThis.ts | 11 ++++ 4 files changed, 127 insertions(+) create mode 100644 tests/baselines/reference/instantiateContextuallyTypedGenericThis.js create mode 100644 tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols create mode 100644 tests/baselines/reference/instantiateContextuallyTypedGenericThis.types create mode 100644 tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts diff --git a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.js b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.js new file mode 100644 index 0000000000..0233180873 --- /dev/null +++ b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.js @@ -0,0 +1,20 @@ +//// [instantiateContextuallyTypedGenericThis.ts] +interface JQuery { + each( + collection: T[], callback: (this: T, dit: T) => T + ): any; +} + +let $: JQuery; +let lines: string[]; +$.each(lines, function(dit) { + return dit.charAt(0) + this.charAt(1); +}); + + +//// [instantiateContextuallyTypedGenericThis.js] +var $; +var lines; +$.each(lines, function (dit) { + return dit.charAt(0) + this.charAt(1); +}); diff --git a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols new file mode 100644 index 0000000000..34a477b706 --- /dev/null +++ b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols @@ -0,0 +1,44 @@ +=== tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts === +interface JQuery { +>JQuery : Symbol(JQuery, Decl(instantiateContextuallyTypedGenericThis.ts, 0, 0)) + + each( +>each : Symbol(JQuery.each, Decl(instantiateContextuallyTypedGenericThis.ts, 0, 18)) +>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) + + collection: T[], callback: (this: T, dit: T) => T +>collection : Symbol(collection, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 12)) +>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) +>callback : Symbol(callback, Decl(instantiateContextuallyTypedGenericThis.ts, 2, 24)) +>this : Symbol(this, Decl(instantiateContextuallyTypedGenericThis.ts, 2, 36)) +>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) +>dit : Symbol(dit, Decl(instantiateContextuallyTypedGenericThis.ts, 2, 44)) +>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) +>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) + + ): any; +} + +let $: JQuery; +>$ : Symbol($, Decl(instantiateContextuallyTypedGenericThis.ts, 6, 3)) +>JQuery : Symbol(JQuery, Decl(instantiateContextuallyTypedGenericThis.ts, 0, 0)) + +let lines: string[]; +>lines : Symbol(lines, Decl(instantiateContextuallyTypedGenericThis.ts, 7, 3)) + +$.each(lines, function(dit) { +>$.each : Symbol(JQuery.each, Decl(instantiateContextuallyTypedGenericThis.ts, 0, 18)) +>$ : Symbol($, Decl(instantiateContextuallyTypedGenericThis.ts, 6, 3)) +>each : Symbol(JQuery.each, Decl(instantiateContextuallyTypedGenericThis.ts, 0, 18)) +>lines : Symbol(lines, Decl(instantiateContextuallyTypedGenericThis.ts, 7, 3)) +>dit : Symbol(dit, Decl(instantiateContextuallyTypedGenericThis.ts, 8, 23)) + + return dit.charAt(0) + this.charAt(1); +>dit.charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --)) +>dit : Symbol(dit, Decl(instantiateContextuallyTypedGenericThis.ts, 8, 23)) +>charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --)) +>this.charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --)) +>charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --)) + +}); + diff --git a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.types b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.types new file mode 100644 index 0000000000..060d35be21 --- /dev/null +++ b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.types @@ -0,0 +1,52 @@ +=== tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts === +interface JQuery { +>JQuery : JQuery + + each( +>each : (collection: T[], callback: (this: T, dit: T) => T) => any +>T : T + + collection: T[], callback: (this: T, dit: T) => T +>collection : T[] +>T : T +>callback : (this: T, dit: T) => T +>this : T +>T : T +>dit : T +>T : T +>T : T + + ): any; +} + +let $: JQuery; +>$ : JQuery +>JQuery : JQuery + +let lines: string[]; +>lines : string[] + +$.each(lines, function(dit) { +>$.each(lines, function(dit) { return dit.charAt(0) + this.charAt(1);}) : any +>$.each : (collection: T[], callback: (this: T, dit: T) => T) => any +>$ : JQuery +>each : (collection: T[], callback: (this: T, dit: T) => T) => any +>lines : string[] +>function(dit) { return dit.charAt(0) + this.charAt(1);} : (dit: string) => string +>dit : string + + return dit.charAt(0) + this.charAt(1); +>dit.charAt(0) + this.charAt(1) : string +>dit.charAt(0) : string +>dit.charAt : (pos: number) => string +>dit : string +>charAt : (pos: number) => string +>0 : number +>this.charAt(1) : string +>this.charAt : (pos: number) => string +>this : string +>charAt : (pos: number) => string +>1 : number + +}); + diff --git a/tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts b/tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts new file mode 100644 index 0000000000..f25e66ecfb --- /dev/null +++ b/tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts @@ -0,0 +1,11 @@ +interface JQuery { + each( + collection: T[], callback: (this: T, dit: T) => T + ): any; +} + +let $: JQuery; +let lines: string[]; +$.each(lines, function(dit) { + return dit.charAt(0) + this.charAt(1); +}); From 448a480aa8d592378732b1052c645b5c681fa7e3 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 12 Jul 2016 08:37:52 -0700 Subject: [PATCH 06/50] Don't allow `.ts` to appear in an import --- src/compiler/program.ts | 61 +++++++++++-------- src/harness/unittests/moduleResolution.ts | 8 +-- .../missingFunctionImplementation2.errors.txt | 2 +- .../missingFunctionImplementation2.js | 2 +- .../reference/moduleResolutionNoTs.errors.txt | 11 ++++ .../reference/moduleResolutionNoTs.js | 15 +++++ .../moduleResolutionWithExtensions.js | 7 --- .../moduleResolutionWithExtensions.symbols | 5 -- .../moduleResolutionWithExtensions.trace.json | 6 -- .../moduleResolutionWithExtensions.types | 5 -- .../staticInstanceResolution5.errors.txt | 2 +- .../reference/staticInstanceResolution5.js | 2 +- .../missingFunctionImplementation2.ts | 2 +- tests/cases/compiler/moduleResolutionNoTs.ts | 5 ++ .../compiler/staticInstanceResolution5.ts | 2 +- .../moduleResolutionWithExtensions.ts | 4 -- 16 files changed, 77 insertions(+), 62 deletions(-) create mode 100644 tests/baselines/reference/moduleResolutionNoTs.errors.txt create mode 100644 tests/baselines/reference/moduleResolutionNoTs.js create mode 100644 tests/cases/compiler/moduleResolutionNoTs.ts diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 988714be2a..5ddf5f7d06 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -668,24 +668,37 @@ namespace ts { * @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ - function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string { - // First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts" - const resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); - if (resolvedByAddingOrKeepingExtension) { - return resolvedByAddingOrKeepingExtension; + function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { + // If the candidate already has an extension load that or quit. + if (hasTypeScriptFileExtension(candidate)) { + // Don't allow `.ts` to appear at the end + if (!fileExtensionIs(candidate, ".d.ts")) { + return undefined; + } + return tryFile(candidate, failedLookupLocation, onlyRecordFailures, state); } - // Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" + + // Next, try adding an extension. + // We don't allow an import of "foo.ts" to be matched by "foo.ts.ts", but we do allow "foo.js" to be matched by "foo.js.ts". + const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); + if (resolvedByAddingExtension) { + return resolvedByAddingExtension; + } + + // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one; + // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" if (hasJavaScriptFileExtension(candidate)) { const extensionless = removeFileExtension(candidate); if (state.traceEnabled) { const extension = candidate.substring(extensionless.length); trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension); } - return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); + return tryAddingExtensions(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state); } } - function loadModuleFromFileWorker(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string { + /** Try to return an existing file that adds one of the `extensions` to `candidate`. */ + function tryAddingExtensions(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { if (!onlyRecordFailures) { // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing const directory = getDirectoryPath(candidate); @@ -693,26 +706,24 @@ namespace ts { onlyRecordFailures = !directoryProbablyExists(directory, state.host); } } - return forEach(extensions, tryLoad); + return forEach(extensions, ext => + !(state.skipTsx && isJsxOrTsxExtension(ext)) && tryFile(candidate + ext, failedLookupLocation, onlyRecordFailures, state)); + } - function tryLoad(ext: string): string { - if (state.skipTsx && isJsxOrTsxExtension(ext)) { - return undefined; + /** Return the file if it exists. */ + function tryFile(fileName: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { + if (!onlyRecordFailures && state.host.fileExists(fileName)) { + if (state.traceEnabled) { + trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); } - const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext; - if (!onlyRecordFailures && state.host.fileExists(fileName)) { - if (state.traceEnabled) { - trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName); - } - return fileName; - } - else { - if (state.traceEnabled) { - trace(state.host, Diagnostics.File_0_does_not_exist, fileName); - } - failedLookupLocation.push(fileName); - return undefined; + return fileName; + } + else { + if (state.traceEnabled) { + trace(state.host, Diagnostics.File_0_does_not_exist, fileName); } + failedLookupLocation.push(fileName); + return undefined; } } diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index b3f2102d90..0c312f4701 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -465,8 +465,8 @@ export = C; "/a/B/c/moduleB.ts": `import a = require("./moduleC")`, "/a/B/c/moduleC.ts": "export var x", "/a/B/c/moduleD.ts": ` -import a = require("./moduleA.ts"); -import b = require("./moduleB.ts"); +import a = require("./moduleA"); +import b = require("./moduleB"); ` }; test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], [1149]); @@ -477,8 +477,8 @@ import b = require("./moduleB.ts"); "/a/B/c/moduleB.ts": `import a = require("./moduleC")`, "/a/B/c/moduleC.ts": "export var x", "/a/B/c/moduleD.ts": ` -import a = require("./moduleA.ts"); -import b = require("./moduleB.ts"); +import a = require("./moduleA"); +import b = require("./moduleB"); ` }; test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], []); diff --git a/tests/baselines/reference/missingFunctionImplementation2.errors.txt b/tests/baselines/reference/missingFunctionImplementation2.errors.txt index a695482e1f..86d8baba6f 100644 --- a/tests/baselines/reference/missingFunctionImplementation2.errors.txt +++ b/tests/baselines/reference/missingFunctionImplementation2.errors.txt @@ -4,7 +4,7 @@ tests/cases/compiler/missingFunctionImplementation2_b.ts(1,17): error TS2391: Fu ==== tests/cases/compiler/missingFunctionImplementation2_a.ts (1 errors) ==== export {}; - declare module "./missingFunctionImplementation2_b.ts" { + declare module "./missingFunctionImplementation2_b" { export function f(a, b): void; ~ !!! error TS2384: Overload signatures must all be ambient or non-ambient. diff --git a/tests/baselines/reference/missingFunctionImplementation2.js b/tests/baselines/reference/missingFunctionImplementation2.js index 104b6dd944..7b3456015c 100644 --- a/tests/baselines/reference/missingFunctionImplementation2.js +++ b/tests/baselines/reference/missingFunctionImplementation2.js @@ -2,7 +2,7 @@ //// [missingFunctionImplementation2_a.ts] export {}; -declare module "./missingFunctionImplementation2_b.ts" { +declare module "./missingFunctionImplementation2_b" { export function f(a, b): void; } diff --git a/tests/baselines/reference/moduleResolutionNoTs.errors.txt b/tests/baselines/reference/moduleResolutionNoTs.errors.txt new file mode 100644 index 0000000000..d1d6270ae1 --- /dev/null +++ b/tests/baselines/reference/moduleResolutionNoTs.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/user.ts(1,15): error TS2307: Cannot find module './m.ts'. + + +==== tests/cases/compiler/m.ts (0 errors) ==== + export default 0; + +==== tests/cases/compiler/user.ts (1 errors) ==== + import x from "./m.ts"; + ~~~~~~~~ +!!! error TS2307: Cannot find module './m.ts'. + \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionNoTs.js b/tests/baselines/reference/moduleResolutionNoTs.js new file mode 100644 index 0000000000..2a56947ce1 --- /dev/null +++ b/tests/baselines/reference/moduleResolutionNoTs.js @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/moduleResolutionNoTs.ts] //// + +//// [m.ts] +export default 0; + +//// [user.ts] +import x from "./m.ts"; + + +//// [m.js] +"use strict"; +exports.__esModule = true; +exports["default"] = 0; +//// [user.js] +"use strict"; diff --git a/tests/baselines/reference/moduleResolutionWithExtensions.js b/tests/baselines/reference/moduleResolutionWithExtensions.js index df12a3531b..16d176872c 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions.js +++ b/tests/baselines/reference/moduleResolutionWithExtensions.js @@ -8,10 +8,6 @@ export default 0; //// [b.ts] import a from './a'; -// Matching extension -//// [c.ts] -import a from './a.ts'; - // '.js' extension: stripped and replaced with '.ts' //// [d.ts] import a from './a.js'; @@ -36,9 +32,6 @@ exports["default"] = 0; // No extension: '.ts' added //// [b.js] "use strict"; -// Matching extension -//// [c.js] -"use strict"; // '.js' extension: stripped and replaced with '.ts' //// [d.js] "use strict"; diff --git a/tests/baselines/reference/moduleResolutionWithExtensions.symbols b/tests/baselines/reference/moduleResolutionWithExtensions.symbols index e9934946a6..eaaa1d51cc 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions.symbols +++ b/tests/baselines/reference/moduleResolutionWithExtensions.symbols @@ -7,11 +7,6 @@ No type information for this code.=== /src/b.ts === import a from './a'; >a : Symbol(a, Decl(b.ts, 0, 6)) -// Matching extension -=== /src/c.ts === -import a from './a.ts'; ->a : Symbol(a, Decl(c.ts, 0, 6)) - // '.js' extension: stripped and replaced with '.ts' === /src/d.ts === import a from './a.js'; diff --git a/tests/baselines/reference/moduleResolutionWithExtensions.trace.json b/tests/baselines/reference/moduleResolutionWithExtensions.trace.json index 7dc9e8c104..5060006ac5 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions.trace.json +++ b/tests/baselines/reference/moduleResolutionWithExtensions.trace.json @@ -5,12 +5,6 @@ "File '/src/a.ts' exist - use it as a name resolution result.", "Resolving real path for '/src/a.ts', result '/src/a.ts'", "======== Module name './a' was successfully resolved to '/src/a.ts'. ========", - "======== Resolving module './a.ts' from '/src/c.ts'. ========", - "Module resolution kind is not specified, using 'NodeJs'.", - "Loading module as file / folder, candidate module location '/src/a.ts'.", - "File '/src/a.ts' exist - use it as a name resolution result.", - "Resolving real path for '/src/a.ts', result '/src/a.ts'", - "======== Module name './a.ts' was successfully resolved to '/src/a.ts'. ========", "======== Resolving module './a.js' from '/src/d.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module as file / folder, candidate module location '/src/a.js'.", diff --git a/tests/baselines/reference/moduleResolutionWithExtensions.types b/tests/baselines/reference/moduleResolutionWithExtensions.types index fbc0091ee3..f59eda1a81 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions.types +++ b/tests/baselines/reference/moduleResolutionWithExtensions.types @@ -7,11 +7,6 @@ No type information for this code.=== /src/b.ts === import a from './a'; >a : number -// Matching extension -=== /src/c.ts === -import a from './a.ts'; ->a : number - // '.js' extension: stripped and replaced with '.ts' === /src/d.ts === import a from './a.js'; diff --git a/tests/baselines/reference/staticInstanceResolution5.errors.txt b/tests/baselines/reference/staticInstanceResolution5.errors.txt index da6f0fde14..f36851b2b9 100644 --- a/tests/baselines/reference/staticInstanceResolution5.errors.txt +++ b/tests/baselines/reference/staticInstanceResolution5.errors.txt @@ -4,7 +4,7 @@ tests/cases/compiler/staticInstanceResolution5_1.ts(6,16): error TS2304: Cannot ==== tests/cases/compiler/staticInstanceResolution5_1.ts (3 errors) ==== - import WinJS = require('staticInstanceResolution5_0.ts'); + import WinJS = require('staticInstanceResolution5_0'); // these 3 should be errors var x = (w1: WinJS) => { }; diff --git a/tests/baselines/reference/staticInstanceResolution5.js b/tests/baselines/reference/staticInstanceResolution5.js index 0809d1af5f..b3514e00aa 100644 --- a/tests/baselines/reference/staticInstanceResolution5.js +++ b/tests/baselines/reference/staticInstanceResolution5.js @@ -8,7 +8,7 @@ export class Promise { } //// [staticInstanceResolution5_1.ts] -import WinJS = require('staticInstanceResolution5_0.ts'); +import WinJS = require('staticInstanceResolution5_0'); // these 3 should be errors var x = (w1: WinJS) => { }; diff --git a/tests/cases/compiler/missingFunctionImplementation2.ts b/tests/cases/compiler/missingFunctionImplementation2.ts index 25909b6add..1717bc663f 100644 --- a/tests/cases/compiler/missingFunctionImplementation2.ts +++ b/tests/cases/compiler/missingFunctionImplementation2.ts @@ -1,6 +1,6 @@ // @Filename: missingFunctionImplementation2_a.ts export {}; -declare module "./missingFunctionImplementation2_b.ts" { +declare module "./missingFunctionImplementation2_b" { export function f(a, b): void; } diff --git a/tests/cases/compiler/moduleResolutionNoTs.ts b/tests/cases/compiler/moduleResolutionNoTs.ts new file mode 100644 index 0000000000..18b042d905 --- /dev/null +++ b/tests/cases/compiler/moduleResolutionNoTs.ts @@ -0,0 +1,5 @@ +// @filename: m.ts +export default 0; + +// @filename: user.ts +import x from "./m.ts"; diff --git a/tests/cases/compiler/staticInstanceResolution5.ts b/tests/cases/compiler/staticInstanceResolution5.ts index 3adb8667be..ed34dbd535 100644 --- a/tests/cases/compiler/staticInstanceResolution5.ts +++ b/tests/cases/compiler/staticInstanceResolution5.ts @@ -7,7 +7,7 @@ export class Promise { } // @Filename: staticInstanceResolution5_1.ts -import WinJS = require('staticInstanceResolution5_0.ts'); +import WinJS = require('staticInstanceResolution5_0'); // these 3 should be errors var x = (w1: WinJS) => { }; diff --git a/tests/cases/conformance/externalModules/moduleResolutionWithExtensions.ts b/tests/cases/conformance/externalModules/moduleResolutionWithExtensions.ts index 6ad3565862..429289546c 100644 --- a/tests/cases/conformance/externalModules/moduleResolutionWithExtensions.ts +++ b/tests/cases/conformance/externalModules/moduleResolutionWithExtensions.ts @@ -7,10 +7,6 @@ export default 0; // @Filename: /src/b.ts import a from './a'; -// Matching extension -// @Filename: /src/c.ts -import a from './a.ts'; - // '.js' extension: stripped and replaced with '.ts' // @Filename: /src/d.ts import a from './a.js'; From a8c05a98e98b0e2f7d50d983ac08d385d6dd3641 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 12 Jul 2016 11:11:03 -0700 Subject: [PATCH 07/50] Add specific error message for unwanted '.ts' extension --- src/compiler/checker.ts | 7 ++++++- src/compiler/core.ts | 3 ++- src/compiler/diagnosticMessages.json | 4 ++++ src/compiler/utilities.ts | 4 ++++ .../reference/moduleResolutionNoTs.errors.txt | 13 ++++++++----- tests/baselines/reference/moduleResolutionNoTs.js | 5 +++++ tests/cases/compiler/moduleResolutionNoTs.ts | 3 +++ 7 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1cebd46938..88565bcba9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1342,7 +1342,12 @@ namespace ts { if (moduleNotFoundError) { // report errors only if it was requested - error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + if (hasTypeScriptFileExtensionNonDts(moduleName)) { + error(moduleReferenceLiteral, Diagnostics.Module_name_should_not_include_a_ts_extension_Colon_0, moduleName); + } + else { + error(moduleReferenceLiteral, moduleNotFoundError, moduleName); + } } return undefined; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 926ee38a79..9b12f6a7f6 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1144,7 +1144,8 @@ namespace ts { /** * List of supported extensions in order of file resolution precedence. */ - export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"]; + export const supportedTypeScriptExtensionsNonDts = [".ts", ".tsx"]; + export const supportedTypeScriptExtensions = supportedTypeScriptExtensionsNonDts.concat([".d.ts"]); export const supportedJavascriptExtensions = [".js", ".jsx"]; const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 8ffb02a897..d85dc20afd 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1943,6 +1943,10 @@ "category": "Error", "code": 2689 }, + "Module name should not include a '.ts' extension: '{0}'.": { + "category": "Error", + "code": 2690 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", "code": 4000 diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7219a5bbd2..bfe8e4bd65 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2726,6 +2726,10 @@ namespace ts { return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension)); } + export function hasTypeScriptFileExtensionNonDts(fileName: string) { + return forEach(supportedTypeScriptExtensionsNonDts, extension => fileExtensionIs(fileName, extension)); + } + /** * Replace each instance of non-ascii characters by one, two, three, or four escape sequences * representing the UTF-8 encoding of the character, and return the expanded char code list. diff --git a/tests/baselines/reference/moduleResolutionNoTs.errors.txt b/tests/baselines/reference/moduleResolutionNoTs.errors.txt index d1d6270ae1..de105f7353 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.errors.txt +++ b/tests/baselines/reference/moduleResolutionNoTs.errors.txt @@ -1,11 +1,14 @@ -tests/cases/compiler/user.ts(1,15): error TS2307: Cannot find module './m.ts'. +tests/cases/compiler/user.ts(4,15): error TS2690: Module name should not include a '.ts' extension: './m.ts'. -==== tests/cases/compiler/m.ts (0 errors) ==== - export default 0; - ==== tests/cases/compiler/user.ts (1 errors) ==== + // '.ts' extension is OK in a reference + /// + import x from "./m.ts"; ~~~~~~~~ -!!! error TS2307: Cannot find module './m.ts'. +!!! error TS2690: Module name should not include a '.ts' extension: './m.ts'. + +==== tests/cases/compiler/m.ts (0 errors) ==== + export default 0; \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionNoTs.js b/tests/baselines/reference/moduleResolutionNoTs.js index 2a56947ce1..8a912f3301 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.js +++ b/tests/baselines/reference/moduleResolutionNoTs.js @@ -4,6 +4,9 @@ export default 0; //// [user.ts] +// '.ts' extension is OK in a reference +/// + import x from "./m.ts"; @@ -12,4 +15,6 @@ import x from "./m.ts"; exports.__esModule = true; exports["default"] = 0; //// [user.js] +// '.ts' extension is OK in a reference +/// "use strict"; diff --git a/tests/cases/compiler/moduleResolutionNoTs.ts b/tests/cases/compiler/moduleResolutionNoTs.ts index 18b042d905..29d81589cd 100644 --- a/tests/cases/compiler/moduleResolutionNoTs.ts +++ b/tests/cases/compiler/moduleResolutionNoTs.ts @@ -2,4 +2,7 @@ export default 0; // @filename: user.ts +// '.ts' extension is OK in a reference +/// + import x from "./m.ts"; From 95e391ec72f289e5049d7601af758bdc7b0dcc69 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 22 Jul 2016 05:56:05 -0700 Subject: [PATCH 08/50] Allow `await` in a simple unary expression --- src/compiler/parser.ts | 2 ++ tests/baselines/reference/castOfAwait.js | 20 +++++++++++++++++++ tests/baselines/reference/castOfAwait.symbols | 7 +++++++ tests/baselines/reference/castOfAwait.types | 10 ++++++++++ tests/cases/compiler/castOfAwait.ts | 4 ++++ 5 files changed, 43 insertions(+) create mode 100644 tests/baselines/reference/castOfAwait.js create mode 100644 tests/baselines/reference/castOfAwait.symbols create mode 100644 tests/baselines/reference/castOfAwait.types create mode 100644 tests/cases/compiler/castOfAwait.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 774cea60e0..8545273afe 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3400,6 +3400,8 @@ namespace ts { return parseTypeOfExpression(); case SyntaxKind.VoidKeyword: return parseVoidExpression(); + case SyntaxKind.AwaitKeyword: + return parseAwaitExpression(); case SyntaxKind.LessThanToken: // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): diff --git a/tests/baselines/reference/castOfAwait.js b/tests/baselines/reference/castOfAwait.js new file mode 100644 index 0000000000..8833a6aa97 --- /dev/null +++ b/tests/baselines/reference/castOfAwait.js @@ -0,0 +1,20 @@ +//// [castOfAwait.ts] +async function f() { + return await 0; +} + + +//// [castOfAwait.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +function f() { + return __awaiter(this, void 0, void 0, function* () { + return yield 0; + }); +} diff --git a/tests/baselines/reference/castOfAwait.symbols b/tests/baselines/reference/castOfAwait.symbols new file mode 100644 index 0000000000..b6ee77ac79 --- /dev/null +++ b/tests/baselines/reference/castOfAwait.symbols @@ -0,0 +1,7 @@ +=== tests/cases/compiler/castOfAwait.ts === +async function f() { +>f : Symbol(f, Decl(castOfAwait.ts, 0, 0)) + + return await 0; +} + diff --git a/tests/baselines/reference/castOfAwait.types b/tests/baselines/reference/castOfAwait.types new file mode 100644 index 0000000000..7b6d8ef035 --- /dev/null +++ b/tests/baselines/reference/castOfAwait.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/castOfAwait.ts === +async function f() { +>f : () => Promise + + return await 0; +> await 0 : number +>await 0 : number +>0 : number +} + diff --git a/tests/cases/compiler/castOfAwait.ts b/tests/cases/compiler/castOfAwait.ts new file mode 100644 index 0000000000..64e96be70f --- /dev/null +++ b/tests/cases/compiler/castOfAwait.ts @@ -0,0 +1,4 @@ +// @target: es6 +async function f() { + return await 0; +} From bc5c7b654ad876f7a75422c58cbbc2d331bdf5f7 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 22 Jul 2016 13:33:22 -0700 Subject: [PATCH 09/50] More tests --- src/compiler/parser.ts | 1 + tests/baselines/reference/castOfAwait.js | 10 ++++++-- tests/baselines/reference/castOfAwait.symbols | 5 +++- tests/baselines/reference/castOfAwait.types | 24 +++++++++++++++++-- .../reference/castOfYield.errors.txt | 12 ++++++++++ tests/baselines/reference/castOfYield.js | 15 ++++++++++++ tests/cases/compiler/castOfAwait.ts | 5 +++- tests/cases/compiler/castOfYield.ts | 5 ++++ 8 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/castOfYield.errors.txt create mode 100644 tests/baselines/reference/castOfYield.js create mode 100644 tests/cases/compiler/castOfYield.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 8545273afe..61c7698c59 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3386,6 +3386,7 @@ namespace ts { * 6) - UnaryExpression[?yield] * 7) ~ UnaryExpression[?yield] * 8) ! UnaryExpression[?yield] + * 9) await AwaitExpression[?yield] */ function parseSimpleUnaryExpression(): UnaryExpression { switch (token) { diff --git a/tests/baselines/reference/castOfAwait.js b/tests/baselines/reference/castOfAwait.js index 8833a6aa97..9d1399d9d6 100644 --- a/tests/baselines/reference/castOfAwait.js +++ b/tests/baselines/reference/castOfAwait.js @@ -1,6 +1,9 @@ //// [castOfAwait.ts] async function f() { - return await 0; + await 0; + typeof await 0; + void await 0; + await void typeof void await 0; } @@ -15,6 +18,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; function f() { return __awaiter(this, void 0, void 0, function* () { - return yield 0; + yield 0; + typeof yield 0; + void yield 0; + yield void typeof void yield 0; }); } diff --git a/tests/baselines/reference/castOfAwait.symbols b/tests/baselines/reference/castOfAwait.symbols index b6ee77ac79..d0bca9f38c 100644 --- a/tests/baselines/reference/castOfAwait.symbols +++ b/tests/baselines/reference/castOfAwait.symbols @@ -2,6 +2,9 @@ async function f() { >f : Symbol(f, Decl(castOfAwait.ts, 0, 0)) - return await 0; + await 0; + typeof await 0; + void await 0; + await void typeof void await 0; } diff --git a/tests/baselines/reference/castOfAwait.types b/tests/baselines/reference/castOfAwait.types index 7b6d8ef035..ba1590fe03 100644 --- a/tests/baselines/reference/castOfAwait.types +++ b/tests/baselines/reference/castOfAwait.types @@ -1,10 +1,30 @@ === tests/cases/compiler/castOfAwait.ts === async function f() { ->f : () => Promise +>f : () => Promise - return await 0; + await 0; > await 0 : number >await 0 : number +>0 : number + + typeof await 0; +>typeof await 0 : string +>await 0 : number +>0 : number + + void await 0; +>void await 0 : undefined +>await 0 : number +>0 : number + + await void typeof void await 0; +>await void typeof void await 0 : any +>void typeof void await 0 : undefined +> typeof void await 0 : string +>typeof void await 0 : string +> void await 0 : number +>void await 0 : undefined +>await 0 : number >0 : number } diff --git a/tests/baselines/reference/castOfYield.errors.txt b/tests/baselines/reference/castOfYield.errors.txt new file mode 100644 index 0000000000..abafe67878 --- /dev/null +++ b/tests/baselines/reference/castOfYield.errors.txt @@ -0,0 +1,12 @@ +tests/cases/compiler/castOfYield.ts(4,14): error TS1109: Expression expected. + + +==== tests/cases/compiler/castOfYield.ts (1 errors) ==== + function* f() { + (yield 0); + // Unlike await, yield is not allowed to appear in a simple unary expression. + yield 0; + ~~~~~ +!!! error TS1109: Expression expected. + } + \ No newline at end of file diff --git a/tests/baselines/reference/castOfYield.js b/tests/baselines/reference/castOfYield.js new file mode 100644 index 0000000000..652cf28e9e --- /dev/null +++ b/tests/baselines/reference/castOfYield.js @@ -0,0 +1,15 @@ +//// [castOfYield.ts] +function* f() { + (yield 0); + // Unlike await, yield is not allowed to appear in a simple unary expression. + yield 0; +} + + +//// [castOfYield.js] +function f() { + (yield 0); + // Unlike await, yield is not allowed to appear in a simple unary expression. + ; + yield 0; +} diff --git a/tests/cases/compiler/castOfAwait.ts b/tests/cases/compiler/castOfAwait.ts index 64e96be70f..6a152226ea 100644 --- a/tests/cases/compiler/castOfAwait.ts +++ b/tests/cases/compiler/castOfAwait.ts @@ -1,4 +1,7 @@ // @target: es6 async function f() { - return await 0; + await 0; + typeof await 0; + void await 0; + await void typeof void await 0; } diff --git a/tests/cases/compiler/castOfYield.ts b/tests/cases/compiler/castOfYield.ts new file mode 100644 index 0000000000..9a85e6b21c --- /dev/null +++ b/tests/cases/compiler/castOfYield.ts @@ -0,0 +1,5 @@ +function* f() { + (yield 0); + // Unlike await, yield is not allowed to appear in a simple unary expression. + yield 0; +} From 275dbc7537accc869da2e47d7f62c519ee223ad4 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 22 Jul 2016 14:01:59 -0700 Subject: [PATCH 10/50] Forbid `await await` --- src/compiler/parser.ts | 5 ++++- .../baselines/reference/awaitAwait.errors.txt | 10 +++++++++ tests/baselines/reference/awaitAwait.js | 21 +++++++++++++++++++ tests/cases/compiler/awaitAwait.ts | 4 ++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/awaitAwait.errors.txt create mode 100644 tests/baselines/reference/awaitAwait.js create mode 100644 tests/cases/compiler/awaitAwait.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 61c7698c59..9c54de6ba1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3337,7 +3337,10 @@ namespace ts { function parseAwaitExpression() { const node = createNode(SyntaxKind.AwaitExpression); nextToken(); - node.expression = parseSimpleUnaryExpression(); + node.expression = token === SyntaxKind.AwaitKeyword + // Forbid `await await` + ? createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Expression_expected) + : parseSimpleUnaryExpression(); return finishNode(node); } diff --git a/tests/baselines/reference/awaitAwait.errors.txt b/tests/baselines/reference/awaitAwait.errors.txt new file mode 100644 index 0000000000..5a04051139 --- /dev/null +++ b/tests/baselines/reference/awaitAwait.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/awaitAwait.ts(2,11): error TS1109: Expression expected. + + +==== tests/cases/compiler/awaitAwait.ts (1 errors) ==== + async function f() { + await await 0; + ~~~~~ +!!! error TS1109: Expression expected. + } + \ No newline at end of file diff --git a/tests/baselines/reference/awaitAwait.js b/tests/baselines/reference/awaitAwait.js new file mode 100644 index 0000000000..14fb3a1150 --- /dev/null +++ b/tests/baselines/reference/awaitAwait.js @@ -0,0 +1,21 @@ +//// [awaitAwait.ts] +async function f() { + await await 0; +} + + +//// [awaitAwait.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +function f() { + return __awaiter(this, void 0, void 0, function* () { + yield ; + yield 0; + }); +} diff --git a/tests/cases/compiler/awaitAwait.ts b/tests/cases/compiler/awaitAwait.ts new file mode 100644 index 0000000000..5a405804b0 --- /dev/null +++ b/tests/cases/compiler/awaitAwait.ts @@ -0,0 +1,4 @@ +// @target: es6 +async function f() { + await await 0; +} From 52fd0334be9439d459757660b4b6cdf1e2778c6d Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 25 Jul 2016 11:08:02 -0700 Subject: [PATCH 11/50] Allow `await await` --- src/compiler/parser.ts | 7 ++----- .../baselines/reference/awaitAwait.errors.txt | 10 --------- tests/baselines/reference/awaitAwait.js | 21 ------------------- tests/baselines/reference/castOfAwait.js | 2 ++ tests/baselines/reference/castOfAwait.symbols | 1 + tests/baselines/reference/castOfAwait.types | 5 +++++ tests/cases/compiler/awaitAwait.ts | 4 ---- tests/cases/compiler/castOfAwait.ts | 1 + 8 files changed, 11 insertions(+), 40 deletions(-) delete mode 100644 tests/baselines/reference/awaitAwait.errors.txt delete mode 100644 tests/baselines/reference/awaitAwait.js delete mode 100644 tests/cases/compiler/awaitAwait.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 9c54de6ba1..68753fdb63 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3337,10 +3337,7 @@ namespace ts { function parseAwaitExpression() { const node = createNode(SyntaxKind.AwaitExpression); nextToken(); - node.expression = token === SyntaxKind.AwaitKeyword - // Forbid `await await` - ? createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Expression_expected) - : parseSimpleUnaryExpression(); + node.expression = parseSimpleUnaryExpression(); return finishNode(node); } @@ -3389,7 +3386,7 @@ namespace ts { * 6) - UnaryExpression[?yield] * 7) ~ UnaryExpression[?yield] * 8) ! UnaryExpression[?yield] - * 9) await AwaitExpression[?yield] + * 9) [+Await] await AwaitExpression[?yield] */ function parseSimpleUnaryExpression(): UnaryExpression { switch (token) { diff --git a/tests/baselines/reference/awaitAwait.errors.txt b/tests/baselines/reference/awaitAwait.errors.txt deleted file mode 100644 index 5a04051139..0000000000 --- a/tests/baselines/reference/awaitAwait.errors.txt +++ /dev/null @@ -1,10 +0,0 @@ -tests/cases/compiler/awaitAwait.ts(2,11): error TS1109: Expression expected. - - -==== tests/cases/compiler/awaitAwait.ts (1 errors) ==== - async function f() { - await await 0; - ~~~~~ -!!! error TS1109: Expression expected. - } - \ No newline at end of file diff --git a/tests/baselines/reference/awaitAwait.js b/tests/baselines/reference/awaitAwait.js deleted file mode 100644 index 14fb3a1150..0000000000 --- a/tests/baselines/reference/awaitAwait.js +++ /dev/null @@ -1,21 +0,0 @@ -//// [awaitAwait.ts] -async function f() { - await await 0; -} - - -//// [awaitAwait.js] -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments)).next()); - }); -}; -function f() { - return __awaiter(this, void 0, void 0, function* () { - yield ; - yield 0; - }); -} diff --git a/tests/baselines/reference/castOfAwait.js b/tests/baselines/reference/castOfAwait.js index 9d1399d9d6..95817b7f0e 100644 --- a/tests/baselines/reference/castOfAwait.js +++ b/tests/baselines/reference/castOfAwait.js @@ -4,6 +4,7 @@ async function f() { typeof await 0; void await 0; await void typeof void await 0; + await await 0; } @@ -22,5 +23,6 @@ function f() { typeof yield 0; void yield 0; yield void typeof void yield 0; + yield yield 0; }); } diff --git a/tests/baselines/reference/castOfAwait.symbols b/tests/baselines/reference/castOfAwait.symbols index d0bca9f38c..574ee21f77 100644 --- a/tests/baselines/reference/castOfAwait.symbols +++ b/tests/baselines/reference/castOfAwait.symbols @@ -6,5 +6,6 @@ async function f() { typeof await 0; void await 0; await void typeof void await 0; + await await 0; } diff --git a/tests/baselines/reference/castOfAwait.types b/tests/baselines/reference/castOfAwait.types index ba1590fe03..ad3597f6c0 100644 --- a/tests/baselines/reference/castOfAwait.types +++ b/tests/baselines/reference/castOfAwait.types @@ -25,6 +25,11 @@ async function f() { > void await 0 : number >void await 0 : undefined >await 0 : number +>0 : number + + await await 0; +>await await 0 : number +>await 0 : number >0 : number } diff --git a/tests/cases/compiler/awaitAwait.ts b/tests/cases/compiler/awaitAwait.ts deleted file mode 100644 index 5a405804b0..0000000000 --- a/tests/cases/compiler/awaitAwait.ts +++ /dev/null @@ -1,4 +0,0 @@ -// @target: es6 -async function f() { - await await 0; -} diff --git a/tests/cases/compiler/castOfAwait.ts b/tests/cases/compiler/castOfAwait.ts index 6a152226ea..fcd8f999e9 100644 --- a/tests/cases/compiler/castOfAwait.ts +++ b/tests/cases/compiler/castOfAwait.ts @@ -4,4 +4,5 @@ async function f() { typeof await 0; void await 0; await void typeof void await 0; + await await 0; } From 0f134ed69efb8d59919bcec6a1e702f403665af6 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 2 Aug 2016 06:58:26 -0700 Subject: [PATCH 12/50] Improve error message --- src/compiler/checker.ts | 6 +++-- src/compiler/core.ts | 21 ++++++++++++++--- src/compiler/diagnosticMessages.json | 2 +- src/compiler/utilities.ts | 5 ++-- .../reference/moduleResolutionNoTs.errors.txt | 23 ++++++++++++++----- .../reference/moduleResolutionNoTs.js | 22 ++++++++++++++---- tests/cases/compiler/moduleResolutionNoTs.ts | 14 ++++++++--- 7 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7eab69f1df..290fa257da 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1366,8 +1366,10 @@ namespace ts { if (moduleNotFoundError) { // report errors only if it was requested - if (hasTypeScriptFileExtensionNonDts(moduleName)) { - error(moduleReferenceLiteral, Diagnostics.Module_name_should_not_include_a_ts_extension_Colon_0, moduleName); + const nonDtsExtension = tryExtractTypeScriptExtensionNonDts(moduleName); + if (nonDtsExtension) { + const diag = Diagnostics.An_import_path_should_not_end_with_a_0_extension_Consider_importing_1_instead; + error(moduleReferenceLiteral, diag, nonDtsExtension, removeExtension(moduleName, nonDtsExtension)); } else { error(moduleReferenceLiteral, moduleNotFoundError, moduleName); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 7d6aea6246..d77036660b 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -93,6 +93,17 @@ namespace ts { return undefined; } + /** Works like Array.prototype.find. */ + export function find(array: T[], predicate: (element: T, index: number) => boolean): T | undefined { + for (let i = 0, len = array.length; i < len; i++) { + const value = array[i]; + if (predicate(value, i)) { + return value; + } + } + return undefined; + } + export function contains(array: T[], value: T): boolean { if (array) { for (const v of array) { @@ -941,7 +952,7 @@ namespace ts { * [^./] # matches everything up to the first . character (excluding directory seperators) * (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension */ - const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*"; + const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*"; const singleAsteriskRegexFragmentOther = "[^/]*"; export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") { @@ -1271,8 +1282,12 @@ namespace ts { return path; } - export function tryRemoveExtension(path: string, extension: string): string { - return fileExtensionIs(path, extension) ? path.substring(0, path.length - extension.length) : undefined; + export function tryRemoveExtension(path: string, extension: string): string | undefined { + return fileExtensionIs(path, extension) ? removeExtension(path, extension) : undefined; + } + + export function removeExtension(path: string, extension: string): string { + return path.substring(0, path.length - extension.length); } export function isJsxOrTsxExtension(ext: string): boolean { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ff534847cd..93bd6c608f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1951,7 +1951,7 @@ "category": "Error", "code": 2690 }, - "Module name should not include a '.ts' extension: '{0}'.": { + "An import path should not end with a '{0}' extension. Consider importing '{1}' instead.": { "category": "Error", "code": 2691 }, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index d6667d2b8b..b92037b7e5 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2726,8 +2726,9 @@ namespace ts { return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension)); } - export function hasTypeScriptFileExtensionNonDts(fileName: string) { - return forEach(supportedTypeScriptExtensionsNonDts, extension => fileExtensionIs(fileName, extension)); + /** Return ".ts" or ".tsx" if that is the extension. */ + export function tryExtractTypeScriptExtensionNonDts(fileName: string): string | undefined { + return find(supportedTypeScriptExtensionsNonDts, extension => fileExtensionIs(fileName, extension)); } /** diff --git a/tests/baselines/reference/moduleResolutionNoTs.errors.txt b/tests/baselines/reference/moduleResolutionNoTs.errors.txt index de105f7353..2a9b74a1af 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.errors.txt +++ b/tests/baselines/reference/moduleResolutionNoTs.errors.txt @@ -1,14 +1,25 @@ -tests/cases/compiler/user.ts(4,15): error TS2690: Module name should not include a '.ts' extension: './m.ts'. +tests/cases/compiler/user.ts(4,15): error TS2691: An import path should not end with a '.ts' extension. Consider importing './x' instead. +tests/cases/compiler/user.ts(5,15): error TS2691: An import path should not end with a '.tsx' extension. Consider importing './y' instead. -==== tests/cases/compiler/user.ts (1 errors) ==== +==== tests/cases/compiler/user.ts (2 errors) ==== // '.ts' extension is OK in a reference - /// + /// - import x from "./m.ts"; + import x from "./x.ts"; ~~~~~~~~ -!!! error TS2690: Module name should not include a '.ts' extension: './m.ts'. +!!! error TS2691: An import path should not end with a '.ts' extension. Consider importing './x' instead. + import y from "./y.tsx"; + ~~~~~~~~~ +!!! error TS2691: An import path should not end with a '.tsx' extension. Consider importing './y' instead. -==== tests/cases/compiler/m.ts (0 errors) ==== + // Making sure the suggested fixes are valid: + import x2 from "./x"; + import y2 from "./y"; + +==== tests/cases/compiler/x.ts (0 errors) ==== + export default 0; + +==== tests/cases/compiler/y.tsx (0 errors) ==== export default 0; \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionNoTs.js b/tests/baselines/reference/moduleResolutionNoTs.js index 8a912f3301..d9d918f560 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.js +++ b/tests/baselines/reference/moduleResolutionNoTs.js @@ -1,20 +1,32 @@ //// [tests/cases/compiler/moduleResolutionNoTs.ts] //// -//// [m.ts] +//// [x.ts] +export default 0; + +//// [y.tsx] export default 0; //// [user.ts] // '.ts' extension is OK in a reference -/// +/// -import x from "./m.ts"; +import x from "./x.ts"; +import y from "./y.tsx"; + +// Making sure the suggested fixes are valid: +import x2 from "./x"; +import y2 from "./y"; -//// [m.js] +//// [x.js] +"use strict"; +exports.__esModule = true; +exports["default"] = 0; +//// [y.js] "use strict"; exports.__esModule = true; exports["default"] = 0; //// [user.js] // '.ts' extension is OK in a reference -/// +/// "use strict"; diff --git a/tests/cases/compiler/moduleResolutionNoTs.ts b/tests/cases/compiler/moduleResolutionNoTs.ts index 29d81589cd..683f6630d9 100644 --- a/tests/cases/compiler/moduleResolutionNoTs.ts +++ b/tests/cases/compiler/moduleResolutionNoTs.ts @@ -1,8 +1,16 @@ -// @filename: m.ts +// @filename: x.ts +export default 0; + +// @filename: y.tsx export default 0; // @filename: user.ts // '.ts' extension is OK in a reference -/// +/// -import x from "./m.ts"; +import x from "./x.ts"; +import y from "./y.tsx"; + +// Making sure the suggested fixes are valid: +import x2 from "./x"; +import y2 from "./y"; From 359c8b12ef3a8339940edd9203dcb2a10c08615b Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 3 Aug 2016 07:12:10 -0700 Subject: [PATCH 13/50] Don't allow ".d.ts" extension in an import either. --- src/compiler/checker.ts | 8 ++-- src/compiler/core.ts | 3 +- src/compiler/diagnosticMessages.json | 2 +- src/compiler/program.ts | 16 ++------ src/compiler/utilities.ts | 6 ++- src/harness/compilerRunner.ts | 2 +- .../reference/moduleResolutionNoTs.errors.txt | 40 +++++++++++-------- .../reference/moduleResolutionNoTs.js | 11 ++--- tests/cases/compiler/moduleResolutionNoTs.ts | 9 +++-- 9 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 290fa257da..6dd2747e33 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1366,10 +1366,10 @@ namespace ts { if (moduleNotFoundError) { // report errors only if it was requested - const nonDtsExtension = tryExtractTypeScriptExtensionNonDts(moduleName); - if (nonDtsExtension) { - const diag = Diagnostics.An_import_path_should_not_end_with_a_0_extension_Consider_importing_1_instead; - error(moduleReferenceLiteral, diag, nonDtsExtension, removeExtension(moduleName, nonDtsExtension)); + const tsExtension = tryExtractTypeScriptExtension(moduleName); + if (tsExtension) { + const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + error(moduleReferenceLiteral, diag, tsExtension, removeExtension(moduleName, tsExtension)); } else { error(moduleReferenceLiteral, moduleNotFoundError, moduleName); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index d77036660b..869cddb2d4 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1198,8 +1198,7 @@ namespace ts { /** * List of supported extensions in order of file resolution precedence. */ - export const supportedTypeScriptExtensionsNonDts = [".ts", ".tsx"]; - export const supportedTypeScriptExtensions = supportedTypeScriptExtensionsNonDts.concat([".d.ts"]); + export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"]; export const supportedJavascriptExtensions = [".js", ".jsx"]; const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 93bd6c608f..8975e5daa0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1951,7 +1951,7 @@ "category": "Error", "code": 2690 }, - "An import path should not end with a '{0}' extension. Consider importing '{1}' instead.": { + "An import path cannot end with a '{0}' extension. Consider importing '{1}' instead.": { "category": "Error", "code": 2691 }, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index a2674d7978..d35ce64412 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -669,17 +669,7 @@ namespace ts { * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { - // If the candidate already has an extension load that or quit. - if (hasTypeScriptFileExtension(candidate)) { - // Don't allow `.ts` to appear at the end - if (!fileExtensionIs(candidate, ".d.ts")) { - return undefined; - } - return tryFile(candidate, failedLookupLocation, onlyRecordFailures, state); - } - - // Next, try adding an extension. - // We don't allow an import of "foo.ts" to be matched by "foo.ts.ts", but we do allow "foo.js" to be matched by "foo.js.ts". + // First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts" const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); if (resolvedByAddingExtension) { return resolvedByAddingExtension; @@ -736,7 +726,9 @@ namespace ts { } const typesFile = tryReadTypesSection(packageJsonPath, candidate, state); if (typesFile) { - const result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(typesFile), state.host), state); + const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host); + // The package.json "typings" property must specify the file with extension, so just try that exact filename. + const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state); if (result) { return result; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b92037b7e5..22c9355072 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2727,9 +2727,11 @@ namespace ts { } /** Return ".ts" or ".tsx" if that is the extension. */ - export function tryExtractTypeScriptExtensionNonDts(fileName: string): string | undefined { - return find(supportedTypeScriptExtensionsNonDts, extension => fileExtensionIs(fileName, extension)); + export function tryExtractTypeScriptExtension(fileName: string): string | undefined { + return find(supportedTypescriptExtensionsWithDtsFirst, extension => fileExtensionIs(fileName, extension)); } + // Must have '.d.ts' first because if '.ts' goes first, that will be detected as the extension instead of '.d.ts'. + const supportedTypescriptExtensionsWithDtsFirst = supportedTypeScriptExtensions.slice().reverse(); /** * Replace each instance of non-ascii characters by one, two, three, or four escape sequences diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index ecdc18394b..b8467adda5 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -52,7 +52,7 @@ class CompilerBaselineRunner extends RunnerBase { private makeUnitName(name: string, root: string) { const path = ts.toPath(name, root, (fileName) => Harness.Compiler.getCanonicalFileName(fileName)); const pathStart = ts.toPath(Harness.IO.getCurrentDirectory(), "", (fileName) => Harness.Compiler.getCanonicalFileName(fileName)); - return path.replace(pathStart, "/"); + return pathStart === "" ? path : path.replace(pathStart, "/"); }; public checkTestCodeOutput(fileName: string) { diff --git a/tests/baselines/reference/moduleResolutionNoTs.errors.txt b/tests/baselines/reference/moduleResolutionNoTs.errors.txt index 2a9b74a1af..c054330731 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.errors.txt +++ b/tests/baselines/reference/moduleResolutionNoTs.errors.txt @@ -1,25 +1,31 @@ -tests/cases/compiler/user.ts(4,15): error TS2691: An import path should not end with a '.ts' extension. Consider importing './x' instead. -tests/cases/compiler/user.ts(5,15): error TS2691: An import path should not end with a '.tsx' extension. Consider importing './y' instead. +tests/cases/compiler/user.ts(1,15): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './x' instead. +tests/cases/compiler/user.ts(2,15): error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './y' instead. +tests/cases/compiler/user.ts(3,15): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './z' instead. -==== tests/cases/compiler/user.ts (2 errors) ==== - // '.ts' extension is OK in a reference - /// - - import x from "./x.ts"; - ~~~~~~~~ -!!! error TS2691: An import path should not end with a '.ts' extension. Consider importing './x' instead. - import y from "./y.tsx"; - ~~~~~~~~~ -!!! error TS2691: An import path should not end with a '.tsx' extension. Consider importing './y' instead. - - // Making sure the suggested fixes are valid: - import x2 from "./x"; - import y2 from "./y"; - ==== tests/cases/compiler/x.ts (0 errors) ==== export default 0; ==== tests/cases/compiler/y.tsx (0 errors) ==== export default 0; + +==== tests/cases/compiler/z.d.ts (0 errors) ==== + declare const x: number; + export default x; + +==== tests/cases/compiler/user.ts (3 errors) ==== + import x from "./x.ts"; + ~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.ts' extension. Consider importing './x' instead. + import y from "./y.tsx"; + ~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './y' instead. + import z from "./z.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './z' instead. + + // Making sure the suggested fixes are valid: + import x2 from "./x"; + import y2 from "./y"; + import z2 from "./z"; \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionNoTs.js b/tests/baselines/reference/moduleResolutionNoTs.js index d9d918f560..9ff33d688e 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.js +++ b/tests/baselines/reference/moduleResolutionNoTs.js @@ -6,16 +6,19 @@ export default 0; //// [y.tsx] export default 0; +//// [z.d.ts] +declare const x: number; +export default x; + //// [user.ts] -// '.ts' extension is OK in a reference -/// - import x from "./x.ts"; import y from "./y.tsx"; +import z from "./z.d.ts"; // Making sure the suggested fixes are valid: import x2 from "./x"; import y2 from "./y"; +import z2 from "./z"; //// [x.js] @@ -27,6 +30,4 @@ exports["default"] = 0; exports.__esModule = true; exports["default"] = 0; //// [user.js] -// '.ts' extension is OK in a reference -/// "use strict"; diff --git a/tests/cases/compiler/moduleResolutionNoTs.ts b/tests/cases/compiler/moduleResolutionNoTs.ts index 683f6630d9..2051bc259b 100644 --- a/tests/cases/compiler/moduleResolutionNoTs.ts +++ b/tests/cases/compiler/moduleResolutionNoTs.ts @@ -4,13 +4,16 @@ export default 0; // @filename: y.tsx export default 0; -// @filename: user.ts -// '.ts' extension is OK in a reference -/// +// @filename: z.d.ts +declare const x: number; +export default x; +// @filename: user.ts import x from "./x.ts"; import y from "./y.tsx"; +import z from "./z.d.ts"; // Making sure the suggested fixes are valid: import x2 from "./x"; import y2 from "./y"; +import z2 from "./z"; From 2eb159e269f79f1c7d86723b2a0d9c44739627fd Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 15 Aug 2016 10:34:07 -0700 Subject: [PATCH 14/50] Rename 'find' functions --- src/compiler/checker.ts | 2 +- src/compiler/core.ts | 9 ++++++--- src/compiler/utilities.ts | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 583ae5a1f3..37f13dbf80 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1032,7 +1032,7 @@ namespace ts { } function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration { - return find(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); + return findMap(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); } function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 36db85061b..d2ea69b304 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -110,7 +110,7 @@ namespace ts { } /** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */ - export function tryFind(array: T[], predicate: (element: T, index: number) => boolean): T | undefined { + export function find(array: T[], predicate: (element: T, index: number) => boolean): T | undefined { for (let i = 0, len = array.length; i < len; i++) { const value = array[i]; if (predicate(value, i)) { @@ -120,8 +120,11 @@ namespace ts { return undefined; } - /** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */ - export function find(array: T[], callback: (element: T, index: number) => U | undefined): U { + /** + * Returns the first truthy result of `callback`, or else fails. + * This is like `forEach`, but never returns undefined. + */ + export function findMap(array: T[], callback: (element: T, index: number) => U | undefined): U { for (let i = 0, len = array.length; i < len; i++) { const result = callback(array[i], i); if (result) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0598c34bd7..8b32d5351e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2715,7 +2715,7 @@ namespace ts { /** Return ".ts" or ".tsx" if that is the extension. */ export function tryExtractTypeScriptExtension(fileName: string): string | undefined { - return tryFind(supportedTypescriptExtensionsWithDtsFirst, extension => fileExtensionIs(fileName, extension)); + return find(supportedTypescriptExtensionsWithDtsFirst, extension => fileExtensionIs(fileName, extension)); } // Must have '.d.ts' first because if '.ts' goes first, that will be detected as the extension instead of '.d.ts'. const supportedTypescriptExtensionsWithDtsFirst = supportedTypeScriptExtensions.slice().reverse(); From 0f483d6546296da0dd4805eb7e7cdbdb1f436fd9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 17 Aug 2016 14:21:49 -0700 Subject: [PATCH 15/50] Assign and instantiate contextual this type if not present --- src/compiler/checker.ts | 17 +++-- ...instantiateContextuallyTypedGenericThis.js | 2 +- ...ntiateContextuallyTypedGenericThis.symbols | 4 +- ...tantiateContextuallyTypedGenericThis.types | 13 ++-- .../reference/thisTypeInFunctions.symbols | 18 ++--- .../reference/thisTypeInFunctions.types | 70 +++++++++---------- .../reference/thisTypeInFunctions2.symbols | 7 +- .../reference/thisTypeInFunctions2.types | 6 +- ...instantiateContextuallyTypedGenericThis.ts | 2 +- 9 files changed, 72 insertions(+), 67 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1aeeb1f2c1..17cfdf8976 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4785,9 +4785,6 @@ namespace ts { function getThisTypeOfSignature(signature: Signature): Type | undefined { if (signature.thisParameter) { - if (signature.mapper) { - signature = instantiateSignature(signature, signature.mapper); - } return getTypeOfSymbol(signature.thisParameter); } } @@ -9085,15 +9082,15 @@ namespace ts { return getInferredClassType(classSymbol); } } - const type = getContextuallyTypedThisType(container); - if (type) { - return type; - } const thisType = getThisTypeOfDeclaration(container); if (thisType) { return thisType; } + const type = getContextuallyTypedThisType(container); + if (type) { + return type; + } } if (isClassLike(container.parent)) { const symbol = getSymbolOfNode(container.parent); @@ -12277,8 +12274,10 @@ namespace ts { function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) { const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0); if (context.thisParameter) { - // save the mapper in case we need to type `this` later - context.mapper = mapper; + if (!signature.thisParameter) { + signature.thisParameter = createTransientSymbol(context.thisParameter, undefined); + } + assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper); } for (let i = 0; i < len; i++) { const parameter = signature.parameters[i]; diff --git a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.js b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.js index 0233180873..176df15985 100644 --- a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.js +++ b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.js @@ -2,7 +2,7 @@ interface JQuery { each( collection: T[], callback: (this: T, dit: T) => T - ): any; + ): T[]; } let $: JQuery; diff --git a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols index 34a477b706..1db5b30dd0 100644 --- a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols +++ b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.symbols @@ -16,7 +16,8 @@ interface JQuery { >T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) >T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) - ): any; + ): T[]; +>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9)) } let $: JQuery; @@ -38,6 +39,7 @@ $.each(lines, function(dit) { >dit : Symbol(dit, Decl(instantiateContextuallyTypedGenericThis.ts, 8, 23)) >charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --)) >this.charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --)) +>this : Symbol(this, Decl(instantiateContextuallyTypedGenericThis.ts, 2, 36)) >charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --)) }); diff --git a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.types b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.types index 060d35be21..5cdce6b99f 100644 --- a/tests/baselines/reference/instantiateContextuallyTypedGenericThis.types +++ b/tests/baselines/reference/instantiateContextuallyTypedGenericThis.types @@ -3,7 +3,7 @@ interface JQuery { >JQuery : JQuery each( ->each : (collection: T[], callback: (this: T, dit: T) => T) => any +>each : (collection: T[], callback: (this: T, dit: T) => T) => T[] >T : T collection: T[], callback: (this: T, dit: T) => T @@ -16,7 +16,8 @@ interface JQuery { >T : T >T : T - ): any; + ): T[]; +>T : T } let $: JQuery; @@ -27,12 +28,12 @@ let lines: string[]; >lines : string[] $.each(lines, function(dit) { ->$.each(lines, function(dit) { return dit.charAt(0) + this.charAt(1);}) : any ->$.each : (collection: T[], callback: (this: T, dit: T) => T) => any +>$.each(lines, function(dit) { return dit.charAt(0) + this.charAt(1);}) : string[] +>$.each : (collection: T[], callback: (this: T, dit: T) => T) => T[] >$ : JQuery ->each : (collection: T[], callback: (this: T, dit: T) => T) => any +>each : (collection: T[], callback: (this: T, dit: T) => T) => T[] >lines : string[] ->function(dit) { return dit.charAt(0) + this.charAt(1);} : (dit: string) => string +>function(dit) { return dit.charAt(0) + this.charAt(1);} : (this: string, dit: string) => string >dit : string return dit.charAt(0) + this.charAt(1); diff --git a/tests/baselines/reference/thisTypeInFunctions.symbols b/tests/baselines/reference/thisTypeInFunctions.symbols index 8a0be7427e..ad16785f28 100644 --- a/tests/baselines/reference/thisTypeInFunctions.symbols +++ b/tests/baselines/reference/thisTypeInFunctions.symbols @@ -135,7 +135,7 @@ let impl: I = { return this.a; >this.a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30)) ->this : Symbol(, Decl(thisTypeInFunctions.ts, 24, 28)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 24, 23)) >a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30)) }, @@ -144,7 +144,7 @@ let impl: I = { return this.a; >this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) ->this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 25, 22)) >a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) }, @@ -153,7 +153,7 @@ let impl: I = { return this.a; >this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) ->this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 26, 17)) >a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) }, @@ -173,7 +173,7 @@ impl.explicitStructural = function() { return this.a; }; >impl : Symbol(impl, Decl(thisTypeInFunctions.ts, 37, 3)) >explicitStructural : Symbol(I.explicitStructural, Decl(thisTypeInFunctions.ts, 23, 38)) >this.a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30)) ->this : Symbol(, Decl(thisTypeInFunctions.ts, 24, 28)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 24, 23)) >a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30)) impl.explicitInterface = function() { return this.a; }; @@ -181,7 +181,7 @@ impl.explicitInterface = function() { return this.a; }; >impl : Symbol(impl, Decl(thisTypeInFunctions.ts, 37, 3)) >explicitInterface : Symbol(I.explicitInterface, Decl(thisTypeInFunctions.ts, 24, 50)) >this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) ->this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 25, 22)) >a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) impl.explicitStructural = () => 12; @@ -199,7 +199,7 @@ impl.explicitThis = function () { return this.a; }; >impl : Symbol(impl, Decl(thisTypeInFunctions.ts, 37, 3)) >explicitThis : Symbol(I.explicitThis, Decl(thisTypeInFunctions.ts, 25, 39)) >this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) ->this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 26, 17)) >a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13)) // parameter checking @@ -536,7 +536,7 @@ c.explicitC = function(m) { return this.n + m }; >explicitC : Symbol(C.explicitC, Decl(thisTypeInFunctions.ts, 8, 5)) >m : Symbol(m, Decl(thisTypeInFunctions.ts, 126, 23)) >this.n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9)) ->this : Symbol(C, Decl(thisTypeInFunctions.ts, 3, 1)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 9, 14)) >n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9)) >m : Symbol(m, Decl(thisTypeInFunctions.ts, 126, 23)) @@ -546,7 +546,7 @@ c.explicitProperty = function(m) { return this.n + m }; >explicitProperty : Symbol(C.explicitProperty, Decl(thisTypeInFunctions.ts, 11, 5)) >m : Symbol(m, Decl(thisTypeInFunctions.ts, 127, 30)) >this.n : Symbol(n, Decl(thisTypeInFunctions.ts, 12, 28)) ->this : Symbol(, Decl(thisTypeInFunctions.ts, 12, 26)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 12, 21)) >n : Symbol(n, Decl(thisTypeInFunctions.ts, 12, 28)) >m : Symbol(m, Decl(thisTypeInFunctions.ts, 127, 30)) @@ -556,7 +556,7 @@ c.explicitThis = function(m) { return this.n + m }; >explicitThis : Symbol(C.explicitThis, Decl(thisTypeInFunctions.ts, 5, 14)) >m : Symbol(m, Decl(thisTypeInFunctions.ts, 128, 26)) >this.n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9)) ->this : Symbol(C, Decl(thisTypeInFunctions.ts, 3, 1)) +>this : Symbol(this, Decl(thisTypeInFunctions.ts, 6, 17)) >n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9)) >m : Symbol(m, Decl(thisTypeInFunctions.ts, 128, 26)) diff --git a/tests/baselines/reference/thisTypeInFunctions.types b/tests/baselines/reference/thisTypeInFunctions.types index 24c4fb87ba..863ecbce62 100644 --- a/tests/baselines/reference/thisTypeInFunctions.types +++ b/tests/baselines/reference/thisTypeInFunctions.types @@ -132,7 +132,7 @@ function implicitThis(n: number): number { let impl: I = { >impl : I >I : I ->{ a: 12, explicitVoid2: () => this.a, // ok, this: any because it refers to some outer object (window?) explicitVoid1() { return 12; }, explicitStructural() { return this.a; }, explicitInterface() { return this.a; }, explicitThis() { return this.a; },} : { a: number; explicitVoid2: () => any; explicitVoid1(): number; explicitStructural(): number; explicitInterface(): number; explicitThis(): number; } +>{ a: 12, explicitVoid2: () => this.a, // ok, this: any because it refers to some outer object (window?) explicitVoid1() { return 12; }, explicitStructural() { return this.a; }, explicitInterface() { return this.a; }, explicitThis() { return this.a; },} : { a: number; explicitVoid2: () => any; explicitVoid1(this: void): number; explicitStructural(this: { a: number; }): number; explicitInterface(this: I): number; explicitThis(this: I): number; } a: 12, >a : number @@ -146,11 +146,11 @@ let impl: I = { >a : any explicitVoid1() { return 12; }, ->explicitVoid1 : () => number +>explicitVoid1 : (this: void) => number >12 : number explicitStructural() { ->explicitStructural : () => number +>explicitStructural : (this: { a: number; }) => number return this.a; >this.a : number @@ -159,7 +159,7 @@ let impl: I = { }, explicitInterface() { ->explicitInterface : () => number +>explicitInterface : (this: I) => number return this.a; >this.a : number @@ -168,7 +168,7 @@ let impl: I = { }, explicitThis() { ->explicitThis : () => number +>explicitThis : (this: I) => number return this.a; >this.a : number @@ -178,11 +178,11 @@ let impl: I = { }, } impl.explicitVoid1 = function () { return 12; }; ->impl.explicitVoid1 = function () { return 12; } : () => number +>impl.explicitVoid1 = function () { return 12; } : (this: void) => number >impl.explicitVoid1 : (this: void) => number >impl : I >explicitVoid1 : (this: void) => number ->function () { return 12; } : () => number +>function () { return 12; } : (this: void) => number >12 : number impl.explicitVoid2 = () => 12; @@ -194,21 +194,21 @@ impl.explicitVoid2 = () => 12; >12 : number impl.explicitStructural = function() { return this.a; }; ->impl.explicitStructural = function() { return this.a; } : () => number +>impl.explicitStructural = function() { return this.a; } : (this: { a: number; }) => number >impl.explicitStructural : (this: { a: number; }) => number >impl : I >explicitStructural : (this: { a: number; }) => number ->function() { return this.a; } : () => number +>function() { return this.a; } : (this: { a: number; }) => number >this.a : number >this : { a: number; } >a : number impl.explicitInterface = function() { return this.a; }; ->impl.explicitInterface = function() { return this.a; } : () => number +>impl.explicitInterface = function() { return this.a; } : (this: I) => number >impl.explicitInterface : (this: I) => number >impl : I >explicitInterface : (this: I) => number ->function() { return this.a; } : () => number +>function() { return this.a; } : (this: I) => number >this.a : number >this : I >a : number @@ -230,11 +230,11 @@ impl.explicitInterface = () => 12; >12 : number impl.explicitThis = function () { return this.a; }; ->impl.explicitThis = function () { return this.a; } : () => number +>impl.explicitThis = function () { return this.a; } : (this: I) => number >impl.explicitThis : (this: I) => number >impl : I >explicitThis : (this: I) => number ->function () { return this.a; } : () => number +>function () { return this.a; } : (this: I) => number >this.a : number >this : I >a : number @@ -433,7 +433,7 @@ let unboundToSpecified: (this: { y: number }, x: number) => number = x => x + th >this : { y: number; } >y : number >x : number ->x => x + this.y : (x: number) => any +>x => x + this.y : (this: { y: number; }, x: number) => any >x : number >x + this.y : any >x : number @@ -472,7 +472,7 @@ let specifiedLambda: (this: void, x: number) => number = x => x + 12; >specifiedLambda : (this: void, x: number) => number >this : void >x : number ->x => x + 12 : (x: number) => number +>x => x + 12 : (this: void, x: number) => number >x : number >x + 12 : number >x : number @@ -560,40 +560,40 @@ c.explicitProperty = reconstructed.explicitProperty; // lambdas are assignable to anything c.explicitC = m => m; ->c.explicitC = m => m : (m: number) => number +>c.explicitC = m => m : (this: C, m: number) => number >c.explicitC : (this: C, m: number) => number >c : C >explicitC : (this: C, m: number) => number ->m => m : (m: number) => number +>m => m : (this: C, m: number) => number >m : number >m : number c.explicitThis = m => m; ->c.explicitThis = m => m : (m: number) => number +>c.explicitThis = m => m : (this: C, m: number) => number >c.explicitThis : (this: C, m: number) => number >c : C >explicitThis : (this: C, m: number) => number ->m => m : (m: number) => number +>m => m : (this: C, m: number) => number >m : number >m : number c.explicitProperty = m => m; ->c.explicitProperty = m => m : (m: number) => number +>c.explicitProperty = m => m : (this: { n: number; }, m: number) => number >c.explicitProperty : (this: { n: number; }, m: number) => number >c : C >explicitProperty : (this: { n: number; }, m: number) => number ->m => m : (m: number) => number +>m => m : (this: { n: number; }, m: number) => number >m : number >m : number // this inside lambdas refer to outer scope // the outer-scoped lambda at top-level is still just `any` c.explicitC = m => m + this.n; ->c.explicitC = m => m + this.n : (m: number) => any +>c.explicitC = m => m + this.n : (this: C, m: number) => any >c.explicitC : (this: C, m: number) => number >c : C >explicitC : (this: C, m: number) => number ->m => m + this.n : (m: number) => any +>m => m + this.n : (this: C, m: number) => any >m : number >m + this.n : any >m : number @@ -602,11 +602,11 @@ c.explicitC = m => m + this.n; >n : any c.explicitThis = m => m + this.n; ->c.explicitThis = m => m + this.n : (m: number) => any +>c.explicitThis = m => m + this.n : (this: C, m: number) => any >c.explicitThis : (this: C, m: number) => number >c : C >explicitThis : (this: C, m: number) => number ->m => m + this.n : (m: number) => any +>m => m + this.n : (this: C, m: number) => any >m : number >m + this.n : any >m : number @@ -615,11 +615,11 @@ c.explicitThis = m => m + this.n; >n : any c.explicitProperty = m => m + this.n; ->c.explicitProperty = m => m + this.n : (m: number) => any +>c.explicitProperty = m => m + this.n : (this: { n: number; }, m: number) => any >c.explicitProperty : (this: { n: number; }, m: number) => number >c : C >explicitProperty : (this: { n: number; }, m: number) => number ->m => m + this.n : (m: number) => any +>m => m + this.n : (this: { n: number; }, m: number) => any >m : number >m + this.n : any >m : number @@ -652,11 +652,11 @@ c.explicitThis = function(this: C, m: number) { return this.n + m }; // this:any compatibility c.explicitC = function(m) { return this.n + m }; ->c.explicitC = function(m) { return this.n + m } : (m: number) => number +>c.explicitC = function(m) { return this.n + m } : (this: C, m: number) => number >c.explicitC : (this: C, m: number) => number >c : C >explicitC : (this: C, m: number) => number ->function(m) { return this.n + m } : (m: number) => number +>function(m) { return this.n + m } : (this: C, m: number) => number >m : number >this.n + m : number >this.n : number @@ -665,11 +665,11 @@ c.explicitC = function(m) { return this.n + m }; >m : number c.explicitProperty = function(m) { return this.n + m }; ->c.explicitProperty = function(m) { return this.n + m } : (m: number) => number +>c.explicitProperty = function(m) { return this.n + m } : (this: { n: number; }, m: number) => number >c.explicitProperty : (this: { n: number; }, m: number) => number >c : C >explicitProperty : (this: { n: number; }, m: number) => number ->function(m) { return this.n + m } : (m: number) => number +>function(m) { return this.n + m } : (this: { n: number; }, m: number) => number >m : number >this.n + m : number >this.n : number @@ -678,11 +678,11 @@ c.explicitProperty = function(m) { return this.n + m }; >m : number c.explicitThis = function(m) { return this.n + m }; ->c.explicitThis = function(m) { return this.n + m } : (m: number) => number +>c.explicitThis = function(m) { return this.n + m } : (this: C, m: number) => number >c.explicitThis : (this: C, m: number) => number >c : C >explicitThis : (this: C, m: number) => number ->function(m) { return this.n + m } : (m: number) => number +>function(m) { return this.n + m } : (this: C, m: number) => number >m : number >this.n + m : number >this.n : number @@ -723,11 +723,11 @@ c.explicitC = function(this: B, m: number) { return this.n + m }; // this:void compatibility c.explicitVoid = n => n; ->c.explicitVoid = n => n : (n: number) => number +>c.explicitVoid = n => n : (this: void, n: number) => number >c.explicitVoid : (this: void, m: number) => number >c : C >explicitVoid : (this: void, m: number) => number ->n => n : (n: number) => number +>n => n : (this: void, n: number) => number >n : number >n : number diff --git a/tests/baselines/reference/thisTypeInFunctions2.symbols b/tests/baselines/reference/thisTypeInFunctions2.symbols index cdc7fb321d..5cc26e3ad4 100644 --- a/tests/baselines/reference/thisTypeInFunctions2.symbols +++ b/tests/baselines/reference/thisTypeInFunctions2.symbols @@ -61,12 +61,12 @@ extend1({ >init : Symbol(init, Decl(thisTypeInFunctions2.ts, 20, 9)) this // this: IndexedWithThis because of contextual typing. ->this : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0)) +>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 2, 12)) // this.mine this.willDestroy >this.willDestroy : Symbol(IndexedWithThis.willDestroy, Decl(thisTypeInFunctions2.ts, 2, 32)) ->this : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0)) +>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 2, 12)) >willDestroy : Symbol(IndexedWithThis.willDestroy, Decl(thisTypeInFunctions2.ts, 2, 32)) }, @@ -77,7 +77,10 @@ extend1({ >foo : Symbol(foo, Decl(thisTypeInFunctions2.ts, 26, 13)) this.url; // this: any because 'foo' matches the string indexer +>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 4, 87)) + this.willDestroy; +>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 4, 87)) } }); extend2({ diff --git a/tests/baselines/reference/thisTypeInFunctions2.types b/tests/baselines/reference/thisTypeInFunctions2.types index 371b5f5caf..25fb2f28a6 100644 --- a/tests/baselines/reference/thisTypeInFunctions2.types +++ b/tests/baselines/reference/thisTypeInFunctions2.types @@ -58,10 +58,10 @@ declare function simple(arg: SimpleInterface): void; extend1({ >extend1({ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }}) : void >extend1 : (args: IndexedWithThis) => void ->{ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }} : { init(): void; mine: number; foo(): void; } +>{ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }} : { init(this: IndexedWithThis): void; mine: number; foo(this: any): void; } init() { ->init : () => void +>init : (this: IndexedWithThis) => void this // this: IndexedWithThis because of contextual typing. >this : IndexedWithThis @@ -78,7 +78,7 @@ extend1({ >12 : number foo() { ->foo : () => void +>foo : (this: any) => void this.url; // this: any because 'foo' matches the string indexer >this.url : any diff --git a/tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts b/tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts index f25e66ecfb..f06f06ee7a 100644 --- a/tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts +++ b/tests/cases/compiler/instantiateContextuallyTypedGenericThis.ts @@ -1,7 +1,7 @@ interface JQuery { each( collection: T[], callback: (this: T, dit: T) => T - ): any; + ): T[]; } let $: JQuery; From aa834d7f17933c913015a772b7e0bab1af18dde8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 17 Aug 2016 15:49:57 -0700 Subject: [PATCH 16/50] JSDoc supports null, undefined and never types --- src/compiler/checker.ts | 6 ++++++ src/compiler/parser.ts | 5 ++++- src/compiler/types.ts | 5 ++++- .../reference/jsdocNeverUndefinedNull.js | 20 +++++++++++++++++++ .../reference/jsdocNeverUndefinedNull.symbols | 14 +++++++++++++ .../reference/jsdocNeverUndefinedNull.types | 14 +++++++++++++ .../jsdoc/jsdocNeverUndefinedNull.ts | 11 ++++++++++ 7 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/jsdocNeverUndefinedNull.js create mode 100644 tests/baselines/reference/jsdocNeverUndefinedNull.symbols create mode 100644 tests/baselines/reference/jsdocNeverUndefinedNull.types create mode 100644 tests/cases/conformance/jsdoc/jsdocNeverUndefinedNull.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 01f75dc12d..62a252b6d8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5547,6 +5547,12 @@ namespace ts { return nullType; case SyntaxKind.NeverKeyword: return neverType; + case SyntaxKind.JSDocNullKeyword: + return nullType; + case SyntaxKind.JSDocUndefinedKeyword: + return undefinedType; + case SyntaxKind.JSDocNeverKeyword: + return neverType; case SyntaxKind.ThisType: case SyntaxKind.ThisKeyword: return getTypeFromThisTypeNode(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b05451340d..f78346fd5c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1241,7 +1241,7 @@ namespace ts { // not in error recovery. If we're in error recovery, we don't want an errant // semicolon to be treated as a class member (since they're almost always used // for statements. - return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); + return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); case ParsingContext.EnumMembers: // Include open bracket computed properties. This technically also lets in indexers, // which would be a candidate for improved error reporting. @@ -5890,6 +5890,9 @@ namespace ts { case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.VoidKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.UndefinedKeyword: + case SyntaxKind.NeverKeyword: return parseTokenNode(); case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0bbbd99bdd..1ada1e547f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -351,6 +351,9 @@ namespace ts { JSDocPropertyTag, JSDocTypeLiteral, JSDocLiteralType, + JSDocNullKeyword, + JSDocUndefinedKeyword, + JSDocNeverKeyword, // Synthesized list SyntaxList, @@ -383,7 +386,7 @@ namespace ts { FirstJSDocNode = JSDocTypeExpression, LastJSDocNode = JSDocLiteralType, FirstJSDocTagNode = JSDocComment, - LastJSDocTagNode = JSDocLiteralType + LastJSDocTagNode = JSDocNeverKeyword } export const enum NodeFlags { diff --git a/tests/baselines/reference/jsdocNeverUndefinedNull.js b/tests/baselines/reference/jsdocNeverUndefinedNull.js new file mode 100644 index 0000000000..e57b7091a3 --- /dev/null +++ b/tests/baselines/reference/jsdocNeverUndefinedNull.js @@ -0,0 +1,20 @@ +//// [in.js] +/** + * @param {never} p1 + * @param {undefined} p2 + * @param {null} p3 + * @returns {void} nothing + */ +function f(p1, p2, p3) { +} + + +//// [out.js] +/** + * @param {never} p1 + * @param {undefined} p2 + * @param {null} p3 + * @returns {void} nothing + */ +function f(p1, p2, p3) { +} diff --git a/tests/baselines/reference/jsdocNeverUndefinedNull.symbols b/tests/baselines/reference/jsdocNeverUndefinedNull.symbols new file mode 100644 index 0000000000..a57636ed34 --- /dev/null +++ b/tests/baselines/reference/jsdocNeverUndefinedNull.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/jsdoc/in.js === +/** + * @param {never} p1 + * @param {undefined} p2 + * @param {null} p3 + * @returns {void} nothing + */ +function f(p1, p2, p3) { +>f : Symbol(f, Decl(in.js, 0, 0)) +>p1 : Symbol(p1, Decl(in.js, 6, 11)) +>p2 : Symbol(p2, Decl(in.js, 6, 14)) +>p3 : Symbol(p3, Decl(in.js, 6, 18)) +} + diff --git a/tests/baselines/reference/jsdocNeverUndefinedNull.types b/tests/baselines/reference/jsdocNeverUndefinedNull.types new file mode 100644 index 0000000000..fe57cc298e --- /dev/null +++ b/tests/baselines/reference/jsdocNeverUndefinedNull.types @@ -0,0 +1,14 @@ +=== tests/cases/conformance/jsdoc/in.js === +/** + * @param {never} p1 + * @param {undefined} p2 + * @param {null} p3 + * @returns {void} nothing + */ +function f(p1, p2, p3) { +>f : (p1: never, p2: undefined, p3: null) => void +>p1 : never +>p2 : undefined +>p3 : null +} + diff --git a/tests/cases/conformance/jsdoc/jsdocNeverUndefinedNull.ts b/tests/cases/conformance/jsdoc/jsdocNeverUndefinedNull.ts new file mode 100644 index 0000000000..c095bc1c92 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocNeverUndefinedNull.ts @@ -0,0 +1,11 @@ +// @allowJs: true +// @filename: in.js +// @out: out.js +/** + * @param {never} p1 + * @param {undefined} p2 + * @param {null} p3 + * @returns {void} nothing + */ +function f(p1, p2, p3) { +} From 164beb38d8606e6bf062ca2a0606dffaf8a14f3e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 17 Aug 2016 16:11:45 -0700 Subject: [PATCH 17/50] Update baselines in jsDocParsing unit tests --- src/compiler/parser.ts | 2 +- src/harness/unittests/jsDocParsing.ts | 24 +++++------------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f78346fd5c..ea69a0270c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1241,7 +1241,7 @@ namespace ts { // not in error recovery. If we're in error recovery, we don't want an errant // semicolon to be treated as a class member (since they're almost always used // for statements. - return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); + return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); case ParsingContext.EnumMembers: // Include open bracket computed properties. This technically also lets in indexers, // which would be a candidate for improved error reporting. diff --git a/src/harness/unittests/jsDocParsing.ts b/src/harness/unittests/jsDocParsing.ts index d1ca42f386..a9987ef317 100644 --- a/src/harness/unittests/jsDocParsing.ts +++ b/src/harness/unittests/jsDocParsing.ts @@ -767,16 +767,9 @@ namespace ts { parsesCorrectly( "{null}", `{ - "kind": "JSDocTypeReference", + "kind": "NullKeyword", "pos": 1, - "end": 5, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 5, - "originalKeywordKind": "NullKeyword", - "text": "null" - } + "end": 5 }`); }); @@ -784,16 +777,9 @@ namespace ts { parsesCorrectly( "{undefined}", `{ - "kind": "JSDocTypeReference", + "kind": "UndefinedKeyword", "pos": 1, - "end": 10, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 10, - "originalKeywordKind": "UndefinedKeyword", - "text": "undefined" - } + "end": 10 }`); }); @@ -2379,4 +2365,4 @@ namespace ts { }); }); }); -} \ No newline at end of file +} From d24afc2ad0af8834b635afd8305b44b1f5ad6f77 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Thu, 18 Aug 2016 00:06:48 -0700 Subject: [PATCH 18/50] Return non-JsDocComment children ... to make syntactic classification work --- src/services/services.ts | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 148d3af427..c4b42f9422 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -21,6 +21,7 @@ namespace ts { getChildCount(sourceFile?: SourceFile): number; getChildAt(index: number, sourceFile?: SourceFile): Node; getChildren(sourceFile?: SourceFile): Node[]; + getNonJsDocCommentChildren?(sourceFile?: SourceFile): Node[]; getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number; getFullStart(): number; getEnd(): number; @@ -196,6 +197,7 @@ namespace ts { public parent: Node; public jsDocComments: JSDocComment[]; private _children: Node[]; + private _nonJsDocCommentChildren: Node[]; constructor(kind: SyntaxKind, pos: number, end: number) { this.pos = pos; @@ -273,20 +275,22 @@ namespace ts { } private createChildren(sourceFile?: SourceFile) { - let children: Node[]; + let jsDocCommentChildren: Node[]; + let nonJsDocCommentChildren: Node[]; if (this.kind >= SyntaxKind.FirstNode) { scanner.setText((sourceFile || this.getSourceFile()).text); - children = []; + jsDocCommentChildren = []; + nonJsDocCommentChildren = []; let pos = this.pos; const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode; - const processNode = (node: Node) => { + const processNode = (node: Node, children = nonJsDocCommentChildren) => { if (pos < node.pos) { pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner); } children.push(node); pos = node.end; }; - const processNodes = (nodes: NodeArray) => { + const processNodes = (nodes: NodeArray, children = nonJsDocCommentChildren) => { if (pos < nodes.pos) { pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner); } @@ -296,16 +300,21 @@ namespace ts { // jsDocComments need to be the first children if (this.jsDocComments) { for (const jsDocComment of this.jsDocComments) { - processNode(jsDocComment); + processNode(jsDocComment, jsDocCommentChildren); } } + // For syntactic classifications, all trivia are classcified together, including jsdoc comments. + // For that to work, the jsdoc comments should still be the leading trivia of the first child. + // Restoring the scanner position ensures that. + pos = this.pos; forEachChild(this, processNode, processNodes); if (pos < this.end) { - this.addSyntheticNodes(children, pos, this.end); + this.addSyntheticNodes(nonJsDocCommentChildren, pos, this.end); } scanner.setText(undefined); } - this._children = children || emptyArray; + this._nonJsDocCommentChildren = nonJsDocCommentChildren || emptyArray; + this._children = concatenate(jsDocCommentChildren, this._nonJsDocCommentChildren); } public getChildCount(sourceFile?: SourceFile): number { @@ -323,6 +332,18 @@ namespace ts { return this._children; } + public getNonJsDocCommentChildren(sourceFile?: SourceFile): Node[] { + // If the cached children were cleared, that means some node before the current node has changed. + // so even if we have a cached nonJsDocCommentChildren, it would be outdated as well. + if (!this._children) { + this.createChildren(sourceFile); + } + // If the node has cached children but not nonJsDocCommentChildren, it means the children is not created + // via calling the "createChildren" method, so it can only be a SyntaxList. As SyntaxList cannot have jsDocCommentChildren + // anyways, we can just return its children. + return this._nonJsDocCommentChildren ? this._nonJsDocCommentChildren : this._children; + } + public getFirstToken(sourceFile?: SourceFile): Node { const children = this.getChildren(sourceFile); if (!children.length) { @@ -7725,7 +7746,7 @@ namespace ts { if (decodedTextSpanIntersectsWith(spanStart, spanLength, element.pos, element.getFullWidth())) { checkForClassificationCancellation(element.kind); - const children = element.getChildren(sourceFile); + const children = element.getNonJsDocCommentChildren ? element.getNonJsDocCommentChildren(sourceFile) : element.getChildren(sourceFile); for (let i = 0, n = children.length; i < n; i++) { const child = children[i]; if (!tryClassifyNode(child)) { From 8fc17afa003d53aa7baf914883f2b20606e8a879 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 18 Aug 2016 14:11:30 -0700 Subject: [PATCH 19/50] Move supportedTypescriptExtensionsWithDtsFirst next to supportedTypeScriptExtensions and rename --- src/compiler/core.ts | 2 ++ src/compiler/utilities.ts | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index d2ea69b304..808f8a538d 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1243,6 +1243,8 @@ namespace ts { * List of supported extensions in order of file resolution precedence. */ export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"]; + /** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */ + export const supportedTypescriptExtensionsForExtractExtension = [".d.ts", ".ts", ".tsx"]; export const supportedJavascriptExtensions = [".js", ".jsx"]; const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8b32d5351e..faf210e461 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2713,12 +2713,10 @@ namespace ts { return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension)); } - /** Return ".ts" or ".tsx" if that is the extension. */ + /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ export function tryExtractTypeScriptExtension(fileName: string): string | undefined { - return find(supportedTypescriptExtensionsWithDtsFirst, extension => fileExtensionIs(fileName, extension)); + return find(supportedTypescriptExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension)); } - // Must have '.d.ts' first because if '.ts' goes first, that will be detected as the extension instead of '.d.ts'. - const supportedTypescriptExtensionsWithDtsFirst = supportedTypeScriptExtensions.slice().reverse(); /** * Replace each instance of non-ascii characters by one, two, three, or four escape sequences From 952d2fecc1817eb86d241a9aa6f93ac560be1d27 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 18 Aug 2016 14:19:17 -0700 Subject: [PATCH 20/50] Fix comment --- src/compiler/parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 68753fdb63..361e293011 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3386,7 +3386,7 @@ namespace ts { * 6) - UnaryExpression[?yield] * 7) ~ UnaryExpression[?yield] * 8) ! UnaryExpression[?yield] - * 9) [+Await] await AwaitExpression[?yield] + * 9) [+Await] await UnaryExpression[?yield] */ function parseSimpleUnaryExpression(): UnaryExpression { switch (token) { From 03dcdda44342a07ea10701ae1725f174941d2d97 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 18 Aug 2016 17:12:40 -0700 Subject: [PATCH 21/50] Treat special property access symbol differently ... when retriving documentation --- src/services/services.ts | 18 +++++++++++++++++ .../completionEntryDetailAcrossFiles01.ts | 20 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/cases/fourslash/server/completionEntryDetailAcrossFiles01.ts diff --git a/src/services/services.ts b/src/services/services.ts index ea85caf133..64b872d14a 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4913,6 +4913,24 @@ namespace ts { if (!documentation) { documentation = symbol.getDocumentationComment(); + if ((!documentation || documentation.length === 0) && symbol.flags & SymbolFlags.Property) { + // For some special property access expressions like `experts.foo = foo` or `module.exports.foo = foo` + // there documentation comments might be attached to the right hand side symbol of their declarations. + // The pattern of such special property access is that the parent symbol is the symbol of the file. + if (symbol.parent && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) { + forEach(symbol.declarations, declaration => { + if (declaration.parent && declaration.parent.kind === SyntaxKind.BinaryExpression) { + const rhsSymbol = program.getTypeChecker().getSymbolAtLocation((declaration.parent).right); + if (rhsSymbol) { + documentation = rhsSymbol.getDocumentationComment(); + if (documentation && documentation.length > 0) { + return true; + } + } + } + }); + } + } } return { displayParts, documentation, symbolKind }; diff --git a/tests/cases/fourslash/server/completionEntryDetailAcrossFiles01.ts b/tests/cases/fourslash/server/completionEntryDetailAcrossFiles01.ts new file mode 100644 index 0000000000..243975fde2 --- /dev/null +++ b/tests/cases/fourslash/server/completionEntryDetailAcrossFiles01.ts @@ -0,0 +1,20 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: a.js +//// /** +//// * Modify the parameter +//// * @param {string} p1 +//// */ +//// var foo = function (p1) { } +//// exports.foo = foo; +//// fo/*1*/ + +// @Filename: b.ts +//// import a = require("./a"); +//// a.fo/*2*/ + +goTo.marker('1'); +verify.completionEntryDetailIs("foo", "var foo: (p1: string) => void", "Modify the parameter"); +goTo.marker('2'); +verify.completionEntryDetailIs("foo", "(property) a.foo: (p1: string) => void", "Modify the parameter"); From b452469419cfed00dc5b04f4d286c2c700ef2619 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 19 Aug 2016 06:14:28 -0700 Subject: [PATCH 22/50] Fix tests --- tests/baselines/reference/exportDefaultProperty2.js | 6 +++--- tests/baselines/reference/exportDefaultProperty2.symbols | 2 +- tests/baselines/reference/exportDefaultProperty2.types | 2 +- tests/baselines/reference/exportEqualsProperty2.js | 4 ++-- tests/baselines/reference/exportEqualsProperty2.symbols | 2 +- tests/baselines/reference/exportEqualsProperty2.types | 2 +- tests/cases/compiler/exportDefaultProperty2.ts | 2 +- tests/cases/compiler/exportEqualsProperty2.ts | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/baselines/reference/exportDefaultProperty2.js b/tests/baselines/reference/exportDefaultProperty2.js index 88f0fbb4e2..2b0a5dce52 100644 --- a/tests/baselines/reference/exportDefaultProperty2.js +++ b/tests/baselines/reference/exportDefaultProperty2.js @@ -13,7 +13,7 @@ namespace C { export default C.B; //// [b.ts] -import B from "./a.ts"; +import B from "./a"; const x: B = { c: B }; @@ -29,5 +29,5 @@ exports.__esModule = true; exports["default"] = C.B; //// [b.js] "use strict"; -var a_ts_1 = require("./a.ts"); -var x = { c: a_ts_1["default"] }; +var a_1 = require("./a"); +var x = { c: a_1["default"] }; diff --git a/tests/baselines/reference/exportDefaultProperty2.symbols b/tests/baselines/reference/exportDefaultProperty2.symbols index 7ac99d53a0..d3d7519aa9 100644 --- a/tests/baselines/reference/exportDefaultProperty2.symbols +++ b/tests/baselines/reference/exportDefaultProperty2.symbols @@ -21,7 +21,7 @@ export default C.B; >B : Symbol(default, Decl(a.ts, 2, 9), Decl(a.ts, 5, 13)) === tests/cases/compiler/b.ts === -import B from "./a.ts"; +import B from "./a"; >B : Symbol(B, Decl(b.ts, 0, 6)) const x: B = { c: B }; diff --git a/tests/baselines/reference/exportDefaultProperty2.types b/tests/baselines/reference/exportDefaultProperty2.types index 8dff23f1c8..2fc9d3a475 100644 --- a/tests/baselines/reference/exportDefaultProperty2.types +++ b/tests/baselines/reference/exportDefaultProperty2.types @@ -21,7 +21,7 @@ export default C.B; >B : number === tests/cases/compiler/b.ts === -import B from "./a.ts"; +import B from "./a"; >B : number const x: B = { c: B }; diff --git a/tests/baselines/reference/exportEqualsProperty2.js b/tests/baselines/reference/exportEqualsProperty2.js index 283fa3996a..b5d9143172 100644 --- a/tests/baselines/reference/exportEqualsProperty2.js +++ b/tests/baselines/reference/exportEqualsProperty2.js @@ -13,7 +13,7 @@ namespace C { export = C.B; //// [b.ts] -import B = require("./a.ts"); +import B = require("./a"); const x: B = { c: B }; @@ -28,5 +28,5 @@ var C = (function () { module.exports = C.B; //// [b.js] "use strict"; -var B = require("./a.ts"); +var B = require("./a"); var x = { c: B }; diff --git a/tests/baselines/reference/exportEqualsProperty2.symbols b/tests/baselines/reference/exportEqualsProperty2.symbols index a765e95bdf..df7eda7666 100644 --- a/tests/baselines/reference/exportEqualsProperty2.symbols +++ b/tests/baselines/reference/exportEqualsProperty2.symbols @@ -1,5 +1,5 @@ === tests/cases/compiler/b.ts === -import B = require("./a.ts"); +import B = require("./a"); >B : Symbol(B, Decl(b.ts, 0, 0)) const x: B = { c: B }; diff --git a/tests/baselines/reference/exportEqualsProperty2.types b/tests/baselines/reference/exportEqualsProperty2.types index 90b239e7bb..4594cbfd01 100644 --- a/tests/baselines/reference/exportEqualsProperty2.types +++ b/tests/baselines/reference/exportEqualsProperty2.types @@ -1,5 +1,5 @@ === tests/cases/compiler/b.ts === -import B = require("./a.ts"); +import B = require("./a"); >B : number const x: B = { c: B }; diff --git a/tests/cases/compiler/exportDefaultProperty2.ts b/tests/cases/compiler/exportDefaultProperty2.ts index 180a58a22d..0db617c93e 100644 --- a/tests/cases/compiler/exportDefaultProperty2.ts +++ b/tests/cases/compiler/exportDefaultProperty2.ts @@ -11,5 +11,5 @@ namespace C { export default C.B; // @Filename: b.ts -import B from "./a.ts"; +import B from "./a"; const x: B = { c: B }; diff --git a/tests/cases/compiler/exportEqualsProperty2.ts b/tests/cases/compiler/exportEqualsProperty2.ts index 6a07837334..61f117f162 100644 --- a/tests/cases/compiler/exportEqualsProperty2.ts +++ b/tests/cases/compiler/exportEqualsProperty2.ts @@ -11,5 +11,5 @@ namespace C { export = C.B; // @Filename: b.ts -import B = require("./a.ts"); +import B = require("./a"); const x: B = { c: B }; From 7f6e36c7e1308bc4c87dacb9eb458059d4377b77 Mon Sep 17 00:00:00 2001 From: Yui Date: Fri, 19 Aug 2016 10:03:23 -0700 Subject: [PATCH 23/50] Update shim version to be 2.1 (#10424) --- src/services/shims.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index ff57dd9cf7..9a581ed6be 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -1203,6 +1203,6 @@ namespace TypeScript.Services { // TODO: it should be moved into a namespace though. /* @internal */ -const toolsVersion = "1.9"; +const toolsVersion = "2.1"; /* tslint:enable:no-unused-variable */ From 0168ab2051bc9a364f8f148296cf71848fc4bba9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 19 Aug 2016 13:34:06 -0700 Subject: [PATCH 24/50] Check return code paths on getters (#10102) * Check return paths on getters * Remove TODO comment --- src/compiler/checker.ts | 12 ++--- .../getterControlFlowStrictNull.errors.txt | 27 +++++++++++ .../reference/getterControlFlowStrictNull.js | 47 +++++++++++++++++++ .../compiler/getterControlFlowStrictNull.ts | 20 ++++++++ 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/getterControlFlowStrictNull.errors.txt create mode 100644 tests/baselines/reference/getterControlFlowStrictNull.js create mode 100644 tests/cases/compiler/getterControlFlowStrictNull.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d954ea5117..8568cd5fee 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14126,12 +14126,7 @@ namespace ts { checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { if (!isInAmbientContext(node) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { - if (node.flags & NodeFlags.HasExplicitReturn) { - if (compilerOptions.noImplicitReturns) { - error(node.name, Diagnostics.Not_all_code_paths_return_a_value); - } - } - else { + if (!(node.flags & NodeFlags.HasExplicitReturn)) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value); } } @@ -14161,7 +14156,10 @@ namespace ts { checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type); } } - getTypeOfAccessors(getSymbolOfNode(node)); + const returnType = getTypeOfAccessors(getSymbolOfNode(node)); + if (node.kind === SyntaxKind.GetAccessor) { + checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType); + } } if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { checkSourceElement(node.body); diff --git a/tests/baselines/reference/getterControlFlowStrictNull.errors.txt b/tests/baselines/reference/getterControlFlowStrictNull.errors.txt new file mode 100644 index 0000000000..1c4f02d6a7 --- /dev/null +++ b/tests/baselines/reference/getterControlFlowStrictNull.errors.txt @@ -0,0 +1,27 @@ +tests/cases/compiler/getterControlFlowStrictNull.ts(2,9): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. +tests/cases/compiler/getterControlFlowStrictNull.ts(11,14): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. + + +==== tests/cases/compiler/getterControlFlowStrictNull.ts (2 errors) ==== + class A { + a(): string | null { + ~~~~~~~~~~~~~ +!!! error TS2366: Function lacks ending return statement and return type does not include 'undefined'. + if (Math.random() > 0.5) { + return ''; + } + + // it does error here as expected + } + } + class B { + get a(): string | null { + ~~~~~~~~~~~~~ +!!! error TS2366: Function lacks ending return statement and return type does not include 'undefined'. + if (Math.random() > 0.5) { + return ''; + } + + // it should error here because it returns undefined + } + } \ No newline at end of file diff --git a/tests/baselines/reference/getterControlFlowStrictNull.js b/tests/baselines/reference/getterControlFlowStrictNull.js new file mode 100644 index 0000000000..c3f7e410d0 --- /dev/null +++ b/tests/baselines/reference/getterControlFlowStrictNull.js @@ -0,0 +1,47 @@ +//// [getterControlFlowStrictNull.ts] +class A { + a(): string | null { + if (Math.random() > 0.5) { + return ''; + } + + // it does error here as expected + } +} +class B { + get a(): string | null { + if (Math.random() > 0.5) { + return ''; + } + + // it should error here because it returns undefined + } +} + +//// [getterControlFlowStrictNull.js] +var A = (function () { + function A() { + } + A.prototype.a = function () { + if (Math.random() > 0.5) { + return ''; + } + // it does error here as expected + }; + return A; +}()); +var B = (function () { + function B() { + } + Object.defineProperty(B.prototype, "a", { + get: function () { + if (Math.random() > 0.5) { + return ''; + } + // it should error here because it returns undefined + }, + enumerable: true, + configurable: true + }); + return B; +}()); diff --git a/tests/cases/compiler/getterControlFlowStrictNull.ts b/tests/cases/compiler/getterControlFlowStrictNull.ts new file mode 100644 index 0000000000..44fbe35978 --- /dev/null +++ b/tests/cases/compiler/getterControlFlowStrictNull.ts @@ -0,0 +1,20 @@ +//@strictNullChecks: true +//@target: ES5 +class A { + a(): string | null { + if (Math.random() > 0.5) { + return ''; + } + + // it does error here as expected + } +} +class B { + get a(): string | null { + if (Math.random() > 0.5) { + return ''; + } + + // it should error here because it returns undefined + } +} \ No newline at end of file From da6d95101fd8adfacbdb5209782dc560cf09c62f Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 19 Aug 2016 13:56:27 -0700 Subject: [PATCH 25/50] Remove extraneous arguments from harness's runBaseline (#10419) * Remove extraneous arguments from runBaseline * Address comments from @yuit --- src/harness/compilerRunner.ts | 16 ++-- src/harness/fourslash.ts | 12 +-- src/harness/harness.ts | 84 +++++++++------------ src/harness/projectsRunner.ts | 10 +-- src/harness/rwcRunner.ts | 24 +++--- src/harness/test262Runner.ts | 12 +-- src/harness/unittests/initializeTSConfig.ts | 2 +- src/harness/unittests/transpile.ts | 8 +- 8 files changed, 73 insertions(+), 95 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 66396293dc..88e81ffcf3 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -147,7 +147,7 @@ class CompilerBaselineRunner extends RunnerBase { // check errors it("Correct errors for " + fileName, () => { if (this.errors) { - Harness.Baseline.runBaseline("Correct errors for " + fileName, justName.replace(/\.tsx?$/, ".errors.txt"), (): string => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), (): string => { if (result.errors.length === 0) return null; return getErrorBaseline(toBeCompiled, otherFiles, result); }); @@ -156,7 +156,7 @@ class CompilerBaselineRunner extends RunnerBase { it (`Correct module resolution tracing for ${fileName}`, () => { if (options.traceResolution) { - Harness.Baseline.runBaseline("Correct module resolution tracing for " + fileName, justName.replace(/\.tsx?$/, ".trace.json"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".trace.json"), () => { return JSON.stringify(result.traceResults || [], undefined, 4); }); } @@ -165,7 +165,7 @@ class CompilerBaselineRunner extends RunnerBase { // Source maps? it("Correct sourcemap content for " + fileName, () => { if (options.sourceMap || options.inlineSourceMap) { - Harness.Baseline.runBaseline("Correct sourcemap content for " + fileName, justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => { const record = result.getSourceMapRecord(); if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) { // Because of the noEmitOnError option no files are created. We need to return null because baselining isn"t required. @@ -183,7 +183,7 @@ class CompilerBaselineRunner extends RunnerBase { } // check js output - Harness.Baseline.runBaseline("Correct JS output for " + fileName, justName.replace(/\.tsx?/, ".js"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, ".js"), () => { let tsCode = ""; const tsSources = otherFiles.concat(toBeCompiled); if (tsSources.length > 1) { @@ -242,7 +242,7 @@ class CompilerBaselineRunner extends RunnerBase { throw new Error("Number of sourcemap files should be same as js files."); } - Harness.Baseline.runBaseline("Correct Sourcemap output for " + fileName, justName.replace(/\.tsx?/, ".js.map"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, ".js.map"), () => { if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) { // We need to return null here or the runBaseLine will actually create a empty file. // Baselining isn't required here because there is no output. @@ -330,11 +330,11 @@ class CompilerBaselineRunner extends RunnerBase { const pullExtension = isSymbolBaseLine ? ".symbols.pull" : ".types.pull"; if (fullBaseLine !== pullBaseLine) { - Harness.Baseline.runBaseline("Correct full information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); - Harness.Baseline.runBaseline("Correct pull information for " + fileName, justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine); + Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); + Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine); } else { - Harness.Baseline.runBaseline("Correct information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); + Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); } } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index b5fa53763c..63731417f4 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1132,12 +1132,10 @@ namespace FourSlash { } Harness.Baseline.runBaseline( - "Breakpoint Locations for " + this.activeFile.fileName, baselineFile, () => { return this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)); - }, - true /* run immediately */); + }); } public baselineGetEmitOutput() { @@ -1159,7 +1157,6 @@ namespace FourSlash { } Harness.Baseline.runBaseline( - "Generate getEmitOutput baseline : " + emitFiles.join(" "), this.testData.globalOptions[metadataOptionNames.baselineFile], () => { let resultString = ""; @@ -1185,8 +1182,7 @@ namespace FourSlash { }); return resultString; - }, - true /* run immediately */); + }); } public printBreakpointLocation(pos: number) { @@ -1730,13 +1726,11 @@ namespace FourSlash { public baselineCurrentFileNameOrDottedNameSpans() { Harness.Baseline.runBaseline( - "Name OrDottedNameSpans for " + this.activeFile.fileName, this.testData.globalOptions[metadataOptionNames.baselineFile], () => { return this.baselineCurrentFileLocations(pos => this.getNameOrDottedNameSpan(pos)); - }, - true /* run immediately */); + }); } public printNameOrDottedNameSpans(pos: number) { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index db8c30ddcc..3375b8e47e 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1604,31 +1604,7 @@ namespace Harness { } const fileCache: { [idx: string]: boolean } = {}; - function generateActual(actualFileName: string, generateContent: () => string): string { - // For now this is written using TypeScript, because sys is not available when running old test cases. - // But we need to move to sys once we have - // Creates the directory including its parent if not already present - function createDirectoryStructure(dirName: string) { - if (fileCache[dirName] || IO.directoryExists(dirName)) { - fileCache[dirName] = true; - return; - } - - const parentDirectory = IO.directoryName(dirName); - if (parentDirectory != "") { - createDirectoryStructure(parentDirectory); - } - IO.createDirectory(dirName); - fileCache[dirName] = true; - } - - // Create folders if needed - createDirectoryStructure(Harness.IO.directoryName(actualFileName)); - - // Delete the actual file in case it fails - if (IO.fileExists(actualFileName)) { - IO.deleteFile(actualFileName); - } + function generateActual(generateContent: () => string): string { const actual = generateContent(); @@ -1663,43 +1639,51 @@ namespace Harness { return { expected, actual }; } - function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string, descriptionForDescribe: string) { + function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string) { + // For now this is written using TypeScript, because sys is not available when running old test cases. + // But we need to move to sys once we have + // Creates the directory including its parent if not already present + function createDirectoryStructure(dirName: string) { + if (fileCache[dirName] || IO.directoryExists(dirName)) { + fileCache[dirName] = true; + return; + } + + const parentDirectory = IO.directoryName(dirName); + if (parentDirectory != "") { + createDirectoryStructure(parentDirectory); + } + IO.createDirectory(dirName); + fileCache[dirName] = true; + } + + // Create folders if needed + createDirectoryStructure(Harness.IO.directoryName(actualFileName)); + + // Delete the actual file in case it fails + if (IO.fileExists(actualFileName)) { + IO.deleteFile(actualFileName); + } + const encoded_actual = Utils.encodeString(actual); if (expected !== encoded_actual) { if (actual === NoContent) { - IO.writeFile(localPath(relativeFileName + ".delete"), ""); + IO.writeFile(actualFileName + ".delete", ""); } else { - IO.writeFile(localPath(relativeFileName), actual); + IO.writeFile(actualFileName, actual); } - // Overwrite & issue error - const errMsg = "The baseline file " + relativeFileName + " has changed."; - throw new Error(errMsg); + throw new Error(`The baseline file ${relativeFileName} has changed.`); } } + export function runBaseline(relativeFileName: string, generateContent: () => string, opts?: BaselineOptions): void { - export function runBaseline( - descriptionForDescribe: string, - relativeFileName: string, - generateContent: () => string, - runImmediately = false, - opts?: BaselineOptions): void { - - let actual = undefined; const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder); - if (runImmediately) { - actual = generateActual(actualFileName, generateContent); - const comparison = compareToBaseline(actual, relativeFileName, opts); - writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName, descriptionForDescribe); - } - else { - actual = generateActual(actualFileName, generateContent); - - const comparison = compareToBaseline(actual, relativeFileName, opts); - writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName, descriptionForDescribe); - } + const actual = generateActual(generateContent); + const comparison = compareToBaseline(actual, relativeFileName, opts); + writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName); } } diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index 76f042834b..080c6edfa8 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -459,7 +459,7 @@ class ProjectRunner extends RunnerBase { }); it("Resolution information of (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => { - Harness.Baseline.runBaseline("Resolution information of (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".json", () => { + Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".json", () => { return JSON.stringify(getCompilerResolutionInfo(), undefined, " "); }); }); @@ -467,7 +467,7 @@ class ProjectRunner extends RunnerBase { it("Errors for (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => { if (compilerResult.errors.length) { - Harness.Baseline.runBaseline("Errors for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".errors.txt", () => { + Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".errors.txt", () => { return getErrorsBaseline(compilerResult); }); } @@ -481,7 +481,7 @@ class ProjectRunner extends RunnerBase { // There may be multiple files with different baselines. Run all and report at the end, else // it stops copying the remaining emitted files from 'local/projectOutput' to 'local/project'. try { - Harness.Baseline.runBaseline("Baseline of emitted result (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => { + Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => { try { return Harness.IO.readFile(getProjectOutputFolder(outputFile.fileName, compilerResult.moduleKind)); } @@ -503,7 +503,7 @@ class ProjectRunner extends RunnerBase { it("SourceMapRecord for (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => { if (compilerResult.sourceMapData) { - Harness.Baseline.runBaseline("SourceMapRecord for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".sourcemap.txt", () => { + Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".sourcemap.txt", () => { return Harness.SourceMapRecorder.getSourceMapRecord(compilerResult.sourceMapData, compilerResult.program, ts.filter(compilerResult.outputFiles, outputFile => Harness.Compiler.isJS(outputFile.emittedFileName))); }); @@ -516,7 +516,7 @@ class ProjectRunner extends RunnerBase { if (!compilerResult.errors.length && testCase.declaration) { const dTsCompileResult = compileCompileDTsFiles(compilerResult); if (dTsCompileResult && dTsCompileResult.errors.length) { - Harness.Baseline.runBaseline("Errors in generated Dts files for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".dts.errors.txt", () => { + Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".dts.errors.txt", () => { return getErrorsBaseline(dTsCompileResult); }); } diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 7ea191e3c8..17346016fb 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -158,41 +158,41 @@ namespace RWC { it("has the expected emitted code", () => { - Harness.Baseline.runBaseline("has the expected emitted code", baseName + ".output.js", () => { + Harness.Baseline.runBaseline(baseName + ".output.js", () => { return Harness.Compiler.collateOutputs(compilerResult.files); - }, false, baselineOpts); + }, baselineOpts); }); it("has the expected declaration file content", () => { - Harness.Baseline.runBaseline("has the expected declaration file content", baseName + ".d.ts", () => { + Harness.Baseline.runBaseline(baseName + ".d.ts", () => { if (!compilerResult.declFilesCode.length) { return null; } return Harness.Compiler.collateOutputs(compilerResult.declFilesCode); - }, false, baselineOpts); + }, baselineOpts); }); it("has the expected source maps", () => { - Harness.Baseline.runBaseline("has the expected source maps", baseName + ".map", () => { + Harness.Baseline.runBaseline(baseName + ".map", () => { if (!compilerResult.sourceMaps.length) { return null; } return Harness.Compiler.collateOutputs(compilerResult.sourceMaps); - }, false, baselineOpts); + }, baselineOpts); }); /*it("has correct source map record", () => { if (compilerOptions.sourceMap) { - Harness.Baseline.runBaseline("has correct source map record", baseName + ".sourcemap.txt", () => { + Harness.Baseline.runBaseline(baseName + ".sourcemap.txt", () => { return compilerResult.getSourceMapRecord(); - }, false, baselineOpts); + }, baselineOpts); } });*/ it("has the expected errors", () => { - Harness.Baseline.runBaseline("has the expected errors", baseName + ".errors.txt", () => { + Harness.Baseline.runBaseline(baseName + ".errors.txt", () => { if (compilerResult.errors.length === 0) { return null; } @@ -200,14 +200,14 @@ namespace RWC { const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName)); const errors = compilerResult.errors.filter(e => !Harness.isDefaultLibraryFile(e.file.fileName)); return Harness.Compiler.getErrorBaseline(baselineFiles, errors); - }, false, baselineOpts); + }, baselineOpts); }); // Ideally, a generated declaration file will have no errors. But we allow generated // declaration file errors as part of the baseline. it("has the expected errors in generated declaration files", () => { if (compilerOptions.declaration && !compilerResult.errors.length) { - Harness.Baseline.runBaseline("has the expected errors in generated declaration files", baseName + ".dts.errors.txt", () => { + Harness.Baseline.runBaseline(baseName + ".dts.errors.txt", () => { const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles( inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory); @@ -218,7 +218,7 @@ namespace RWC { return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) + Harness.IO.newLine() + Harness.IO.newLine() + Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors); - }, false, baselineOpts); + }, baselineOpts); } }); diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index c44b2286b8..66cf474824 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -67,21 +67,21 @@ class Test262BaselineRunner extends RunnerBase { }); it("has the expected emitted code", () => { - Harness.Baseline.runBaseline("has the expected emitted code", testState.filename + ".output.js", () => { + Harness.Baseline.runBaseline(testState.filename + ".output.js", () => { const files = testState.compilerResult.files.filter(f => f.fileName !== Test262BaselineRunner.helpersFilePath); return Harness.Compiler.collateOutputs(files); - }, false, Test262BaselineRunner.baselineOptions); + }, Test262BaselineRunner.baselineOptions); }); it("has the expected errors", () => { - Harness.Baseline.runBaseline("has the expected errors", testState.filename + ".errors.txt", () => { + Harness.Baseline.runBaseline(testState.filename + ".errors.txt", () => { const errors = testState.compilerResult.errors; if (errors.length === 0) { return null; } return Harness.Compiler.getErrorBaseline(testState.inputFiles, errors); - }, false, Test262BaselineRunner.baselineOptions); + }, Test262BaselineRunner.baselineOptions); }); it("satisfies invariants", () => { @@ -90,10 +90,10 @@ class Test262BaselineRunner extends RunnerBase { }); it("has the expected AST", () => { - Harness.Baseline.runBaseline("has the expected AST", testState.filename + ".AST.txt", () => { + Harness.Baseline.runBaseline(testState.filename + ".AST.txt", () => { const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); return Utils.sourceFileToJSON(sourceFile); - }, false, Test262BaselineRunner.baselineOptions); + }, Test262BaselineRunner.baselineOptions); }); }); } diff --git a/src/harness/unittests/initializeTSConfig.ts b/src/harness/unittests/initializeTSConfig.ts index 059f07e011..cb995212a9 100644 --- a/src/harness/unittests/initializeTSConfig.ts +++ b/src/harness/unittests/initializeTSConfig.ts @@ -10,7 +10,7 @@ namespace ts { const outputFileName = `tsConfig/${name.replace(/[^a-z0-9\-. ]/ig, "")}/tsconfig.json`; it(`Correct output for ${outputFileName}`, () => { - Harness.Baseline.runBaseline("Correct output", outputFileName, () => { + Harness.Baseline.runBaseline(outputFileName, () => { if (initResult) { return JSON.stringify(initResult, undefined, 4); } diff --git a/src/harness/unittests/transpile.ts b/src/harness/unittests/transpile.ts index 547d10b9fb..2dd9c89a1c 100644 --- a/src/harness/unittests/transpile.ts +++ b/src/harness/unittests/transpile.ts @@ -62,7 +62,7 @@ namespace ts { }); it("Correct errors for " + justName, () => { - Harness.Baseline.runBaseline("Correct errors", justName.replace(/\.tsx?$/, ".errors.txt"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), () => { if (transpileResult.diagnostics.length === 0) { /* tslint:disable:no-null-keyword */ return null; @@ -75,7 +75,7 @@ namespace ts { if (canUseOldTranspile) { it("Correct errors (old transpile) for " + justName, () => { - Harness.Baseline.runBaseline("Correct errors", justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), () => { if (oldTranspileDiagnostics.length === 0) { /* tslint:disable:no-null-keyword */ return null; @@ -88,7 +88,7 @@ namespace ts { } it("Correct output for " + justName, () => { - Harness.Baseline.runBaseline("Correct output", justName.replace(/\.tsx?$/, ".js"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".js"), () => { if (transpileResult.outputText) { return transpileResult.outputText; } @@ -104,7 +104,7 @@ namespace ts { if (canUseOldTranspile) { it("Correct output (old transpile) for " + justName, () => { - Harness.Baseline.runBaseline("Correct output", justName.replace(/\.tsx?$/, ".oldTranspile.js"), () => { + Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.js"), () => { return oldTranspileResult; }); }); From 6c60e5b1050c7c1fcd76c016aaac804368dd6d23 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 19 Aug 2016 14:34:14 -0700 Subject: [PATCH 26/50] Remove needless call to basename --- Jakefile.js | 323 +++++++++++++++++++++++++++------------------------- 1 file changed, 167 insertions(+), 156 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index 441f6aef4f..4c751945c8 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -27,9 +27,9 @@ var thirdParty = "ThirdPartyNoticeText.txt"; // add node_modules to path so we don't need global modules, prefer the modules by adding them first var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter; if (process.env.path !== undefined) { - process.env.path = nodeModulesPathPrefix + process.env.path; + process.env.path = nodeModulesPathPrefix + process.env.path; } else if (process.env.PATH !== undefined) { - process.env.PATH = nodeModulesPathPrefix + process.env.PATH; + process.env.PATH = nodeModulesPathPrefix + process.env.PATH; } function toNs(diff) { @@ -205,11 +205,11 @@ var es2015LibrarySources = [ "es2015.symbol.wellknown.d.ts" ]; -var es2015LibrarySourceMap = es2015LibrarySources.map(function(source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; +var es2015LibrarySourceMap = es2015LibrarySources.map(function (source) { + return { target: "lib." + source, sources: ["header.d.ts", source] }; }); -var es2016LibrarySource = [ "es2016.array.include.d.ts" ]; +var es2016LibrarySource = ["es2016.array.include.d.ts"]; var es2016LibrarySourceMap = es2016LibrarySource.map(function (source) { return { target: "lib." + source, sources: ["header.d.ts", source] }; @@ -227,21 +227,21 @@ var es2017LibrarySourceMap = es2017LibrarySource.map(function (source) { var hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"]; var librarySourceMap = [ - // Host library - { target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] }, - { target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] }, - { target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] }, - { target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] }, + // Host library + { target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] }, + { target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] }, + { target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] }, + { target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] }, - // JavaScript library - { target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] }, - { target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] }, - { target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] }, - { target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] }, + // JavaScript library + { target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] }, + { target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] }, + { target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] }, + { target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] }, - // JavaScript + all host library - { target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) }, - { target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") } + // JavaScript + all host library + { target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) }, + { target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") } ].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap); var libraryTargets = librarySourceMap.map(function (f) { @@ -257,7 +257,7 @@ function prependFile(prefixFile, destinationFile) { fail(destinationFile + " failed to be created!"); } var temp = "temptemp"; - jake.cpR(prefixFile, temp, {silent: true}); + jake.cpR(prefixFile, temp, { silent: true }); fs.appendFileSync(temp, fs.readFileSync(destinationFile)); fs.renameSync(temp, destinationFile); } @@ -269,11 +269,11 @@ function concatenateFiles(destinationFile, sourceFiles) { if (!fs.existsSync(sourceFiles[0])) { fail(sourceFiles[0] + " does not exist!"); } - jake.cpR(sourceFiles[0], temp, {silent: true}); + jake.cpR(sourceFiles[0], temp, { silent: true }); // append all files in sequence for (var i = 1; i < sourceFiles.length; i++) { if (!fs.existsSync(sourceFiles[i])) { - fail(sourceFiles[i] + " does not exist!"); + fail(sourceFiles[i] + " does not exist!"); } fs.appendFileSync(temp, fs.readFileSync(sourceFiles[i])); } @@ -307,11 +307,11 @@ var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename); * @param callback: a function to execute after the compilation process ends */ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts, callback) { - file(outFile, prereqs, function() { + file(outFile, prereqs, function () { var startCompileTime = mark(); opts = opts || {}; var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler; - var options = "--noImplicitAny --noImplicitThis --noEmitOnError --types " + var options = "--noImplicitAny --noImplicitThis --noEmitOnError --types " if (opts.types) { options += opts.types.join(","); } @@ -341,7 +341,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts options += " --module commonjs"; } - if(opts.noResolve) { + if (opts.noResolve) { options += " --noResolve"; } @@ -368,13 +368,13 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts var ex = jake.createExec([cmd]); // Add listeners for output and error - ex.addListener("stdout", function(output) { + ex.addListener("stdout", function (output) { process.stdout.write(output); }); - ex.addListener("stderr", function(error) { + ex.addListener("stderr", function (error) { process.stderr.write(error); }); - ex.addListener("cmdEnd", function() { + ex.addListener("cmdEnd", function () { if (!useDebugMode && prefixes && fs.existsSync(outFile)) { for (var i in prefixes) { prependFile(prefixes[i], outFile); @@ -388,13 +388,13 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts measure(startCompileTime); complete(); }); - ex.addListener("error", function() { + ex.addListener("error", function () { fs.unlinkSync(outFile); fail("Compilation of " + outFile + " unsuccessful"); measure(startCompileTime); }); ex.run(); - }, {async: true}); + }, { async: true }); } // Prerequisite task for built directory and library typings @@ -407,7 +407,7 @@ for (var i in libraryTargets) { var sources = [copyright].concat(entry.sources.map(function (s) { return path.join(libraryDirectory, s); })); - file(target, [builtLocalDirectory].concat(sources), function() { + file(target, [builtLocalDirectory].concat(sources), function () { concatenateFiles(target, sources); }); })(i); @@ -430,30 +430,30 @@ file(processDiagnosticMessagesTs); // processDiagnosticMessages script compileFile(processDiagnosticMessagesJs, - [processDiagnosticMessagesTs], - [processDiagnosticMessagesTs], - [], + [processDiagnosticMessagesTs], + [processDiagnosticMessagesTs], + [], /*useBuiltCompiler*/ false); // The generated diagnostics map; built for the compiler and for the 'generate-diagnostics' task file(diagnosticInfoMapTs, [processDiagnosticMessagesJs, diagnosticMessagesJson], function () { - var cmd = host + " " + processDiagnosticMessagesJs + " " + diagnosticMessagesJson; + var cmd = host + " " + processDiagnosticMessagesJs + " " + diagnosticMessagesJson; console.log(cmd); var ex = jake.createExec([cmd]); // Add listeners for output and error - ex.addListener("stdout", function(output) { + ex.addListener("stdout", function (output) { process.stdout.write(output); }); - ex.addListener("stderr", function(error) { + ex.addListener("stderr", function (error) { process.stderr.write(error); }); - ex.addListener("cmdEnd", function() { + ex.addListener("cmdEnd", function () { complete(); }); ex.run(); -}, {async: true}); +}, { async: true }); -file(builtGeneratedDiagnosticMessagesJSON,[generatedDiagnosticMessagesJSON], function() { +file(builtGeneratedDiagnosticMessagesJSON, [generatedDiagnosticMessagesJSON], function () { if (fs.existsSync(builtLocalDirectory)) { jake.cpR(generatedDiagnosticMessagesJSON, builtGeneratedDiagnosticMessagesJSON); } @@ -471,17 +471,17 @@ var programTs = path.join(compilerDirectory, "program.ts"); file(configureNightlyTs); compileFile(/*outfile*/configureNightlyJs, - /*sources*/ [configureNightlyTs], - /*prereqs*/ [configureNightlyTs], - /*prefixes*/ [], + /*sources*/[configureNightlyTs], + /*prereqs*/[configureNightlyTs], + /*prefixes*/[], /*useBuiltCompiler*/ false, - { noOutFile: false, generateDeclarations: false, keepComments: false, noResolve: false, stripInternal: false }); + { noOutFile: false, generateDeclarations: false, keepComments: false, noResolve: false, stripInternal: false }); -task("setDebugMode", function() { +task("setDebugMode", function () { useDebugMode = true; }); -task("configure-nightly", [configureNightlyJs], function() { +task("configure-nightly", [configureNightlyJs], function () { var cmd = host + " " + configureNightlyJs + " " + packageJson + " " + programTs; console.log(cmd); exec(cmd); @@ -522,63 +522,65 @@ var nodePackageFile = path.join(builtLocalDirectory, "typescript.js"); var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts"); var nodeStandaloneDefinitionsFile = path.join(builtLocalDirectory, "typescript_standalone.d.ts"); -compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources), - /*prefixes*/ [copyright], +compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].concat(servicesSources), + /*prefixes*/[copyright], /*useBuiltCompiler*/ true, - /*opts*/ { noOutFile: false, - generateDeclarations: true, - preserveConstEnums: true, - keepComments: true, - noResolve: false, - stripInternal: true - }, + /*opts*/ { + noOutFile: false, + generateDeclarations: true, + preserveConstEnums: true, + keepComments: true, + noResolve: false, + stripInternal: true + }, /*callback*/ function () { - jake.cpR(servicesFile, nodePackageFile, {silent: true}); + jake.cpR(servicesFile, nodePackageFile, { silent: true }); - prependFile(copyright, standaloneDefinitionsFile); + prependFile(copyright, standaloneDefinitionsFile); - // Stanalone/web definition file using global 'ts' namespace - jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, {silent: true}); - var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString(); - definitionFileContents = definitionFileContents.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4'); - fs.writeFileSync(standaloneDefinitionsFile, definitionFileContents); + // Stanalone/web definition file using global 'ts' namespace + jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, { silent: true }); + var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString(); + definitionFileContents = definitionFileContents.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4'); + fs.writeFileSync(standaloneDefinitionsFile, definitionFileContents); - // Official node package definition file, pointed to by 'typings' in package.json - // Created by appending 'export = ts;' at the end of the standalone file to turn it into an external module - var nodeDefinitionsFileContents = definitionFileContents + "\r\nexport = ts;"; - fs.writeFileSync(nodeDefinitionsFile, nodeDefinitionsFileContents); + // Official node package definition file, pointed to by 'typings' in package.json + // Created by appending 'export = ts;' at the end of the standalone file to turn it into an external module + var nodeDefinitionsFileContents = definitionFileContents + "\r\nexport = ts;"; + fs.writeFileSync(nodeDefinitionsFile, nodeDefinitionsFileContents); - // Node package definition file to be distributed without the package. Created by replacing - // 'ts' namespace with '"typescript"' as a module. - var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts/g, 'declare module "typescript"'); - fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents); - }); + // Node package definition file to be distributed without the package. Created by replacing + // 'ts' namespace with '"typescript"' as a module. + var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts/g, 'declare module "typescript"'); + fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents); + }); compileFile( servicesFileInBrowserTest, servicesSources, [builtLocalDirectory, copyright].concat(servicesSources), - /*prefixes*/ [copyright], + /*prefixes*/[copyright], /*useBuiltCompiler*/ true, - { noOutFile: false, - generateDeclarations: true, - preserveConstEnums: true, - keepComments: true, - noResolve: false, - stripInternal: true, - noMapRoot: true, - inlineSourceMap: true - }); + { + noOutFile: false, + generateDeclarations: true, + preserveConstEnums: true, + keepComments: true, + noResolve: false, + stripInternal: true, + noMapRoot: true, + inlineSourceMap: true + }); var serverFile = path.join(builtLocalDirectory, "tsserver.js"); -compileFile(serverFile, serverSources,[builtLocalDirectory, copyright].concat(serverSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"] }); +compileFile(serverFile, serverSources, [builtLocalDirectory, copyright].concat(serverSources), /*prefixes*/[copyright], /*useBuiltCompiler*/ true, { types: ["node"] }); var tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js"); var tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts"); compileFile( tsserverLibraryFile, languageServiceLibrarySources, [builtLocalDirectory, copyright, builtLocalCompiler].concat(languageServiceLibrarySources).concat(libraryTargets), - /*prefixes*/ [copyright], + /*prefixes*/[copyright], /*useBuiltCompiler*/ true, { noOutFile: false, generateDeclarations: true }); @@ -587,12 +589,12 @@ desc("Builds language service server library"); task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile]); desc("Emit the start of the build fold"); -task("build-fold-start", [] , function() { +task("build-fold-start", [], function () { if (fold.isTravis()) console.log(fold.start("build")); }); desc("Emit the end of the build fold"); -task("build-fold-end", [] , function() { +task("build-fold-end", [], function () { if (fold.isTravis()) console.log(fold.end("build")); }); @@ -606,7 +608,7 @@ task("tsc", ["generate-diagnostics", "lib", tscFile]); // Local target to build the compiler and services desc("Sets release mode flag"); -task("release", function() { +task("release", function () { useDebugMode = false; }); @@ -616,7 +618,7 @@ task("default", ["local"]); // Cleans the built directory desc("Cleans the compiler output, declare files, and tests"); -task("clean", function() { +task("clean", function () { jake.rmRf(builtDirectory); }); @@ -630,9 +632,9 @@ file(word2mdTs); // word2md script compileFile(word2mdJs, - [word2mdTs], - [word2mdTs], - [], + [word2mdTs], + [word2mdTs], + [], /*useBuiltCompiler*/ false); // The generated spec.md; built for the 'generate-spec' task @@ -644,7 +646,7 @@ file(specMd, [word2mdJs, specWord], function () { child_process.exec(cmd, function () { complete(); }); -}, {async: true}); +}, { async: true }); desc("Generates a Markdown version of the Language Specification"); @@ -653,14 +655,14 @@ task("generate-spec", [specMd]); // Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory desc("Makes a new LKG out of the built js files"); -task("LKG", ["clean", "release", "local"].concat(libraryTargets), function() { +task("LKG", ["clean", "release", "local"].concat(libraryTargets), function () { var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile].concat(libraryTargets); var missingFiles = expectedFiles.filter(function (f) { return !fs.existsSync(f); }); if (missingFiles.length > 0) { fail("Cannot replace the LKG unless all built targets are present in directory " + builtLocalDirectory + - ". The following files are missing:\n" + missingFiles.join("\n")); + ". The following files are missing:\n" + missingFiles.join("\n")); } // Copy all the targets into the LKG directory jake.mkdirP(LKGDirectory); @@ -681,8 +683,8 @@ var run = path.join(builtLocalDirectory, "run.js"); compileFile( /*outFile*/ run, /*source*/ harnessSources, - /*prereqs*/ [builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources), - /*prefixes*/ [], + /*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources), + /*prefixes*/[], /*useBuiltCompiler:*/ true, /*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"] }); @@ -701,22 +703,22 @@ desc("Builds the test infrastructure using the built compiler"); task("tests", ["local", run].concat(libraryTargets)); function exec(cmd, completeHandler, errorHandler) { - var ex = jake.createExec([cmd], {windowsVerbatimArguments: true}); + var ex = jake.createExec([cmd], { windowsVerbatimArguments: true }); // Add listeners for output and error - ex.addListener("stdout", function(output) { + ex.addListener("stdout", function (output) { process.stdout.write(output); }); - ex.addListener("stderr", function(error) { + ex.addListener("stderr", function (error) { process.stderr.write(error); }); - ex.addListener("cmdEnd", function() { + ex.addListener("cmdEnd", function () { if (completeHandler) { completeHandler(); } complete(); }); - ex.addListener("error", function(e, status) { - if(errorHandler) { + ex.addListener("error", function (e, status) { + if (errorHandler) { errorHandler(e, status); } else { fail("Process exited with code " + status); @@ -760,7 +762,7 @@ function runConsoleTests(defaultReporter, runInParallel) { tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light || false; var testConfigFile = 'test.config'; - if(fs.existsSync(testConfigFile)) { + if (fs.existsSync(testConfigFile)) { fs.unlinkSync(testConfigFile); } var workerCount, taskConfigsFolder; @@ -793,7 +795,7 @@ function runConsoleTests(defaultReporter, runInParallel) { // timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally // default timeout is 2sec which really should be enough, but maybe we just need a small amount longer - if(!runInParallel) { + if (!runInParallel) { var startTime = mark(); tests = tests ? ' -g "' + tests + '"' : ''; var cmd = "mocha" + (debug ? " --debug-brk" : "") + " -R " + reporter + tests + colors + bail + ' -t ' + testTimeout + ' ' + run; @@ -806,7 +808,7 @@ function runConsoleTests(defaultReporter, runInParallel) { measure(startTime); runLinter(); finish(); - }, function(e, status) { + }, function (e, status) { process.env.NODE_ENV = savedNodeEnv; measure(startTime); finish(status); @@ -860,14 +862,14 @@ function runConsoleTests(defaultReporter, runInParallel) { var testTimeout = 20000; desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true."); -task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function() { +task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function () { runConsoleTests('min', /*runInParallel*/ true); -}, {async: true}); +}, { async: true }); desc("Runs the tests using the built run.js file. Optional arguments are: t[ests]=regex r[eporter]=[list|spec|json|] d[ebug]=true color[s]=false lint=true bail=false."); -task("runtests", ["build-rules", "tests", builtLocalDirectory], function() { +task("runtests", ["build-rules", "tests", builtLocalDirectory], function () { runConsoleTests('mocha-fivemat-progress-reporter', /*runInParallel*/ false); -}, {async: true}); +}, { async: true }); desc("Generates code coverage data via instanbul"); task("generate-code-coverage", ["tests", builtLocalDirectory], function () { @@ -882,23 +884,23 @@ var nodeServerInFile = "tests/webTestServer.ts"; compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true }); desc("Runs browserify on run.js to produce a file suitable for running tests in the browser"); -task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function() { +task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function () { var cmd = 'browserify built/local/run.js -d -o built/local/bundle.js'; exec(cmd); -}, {async: true}); +}, { async: true }); desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], browser=[chrome|IE]"); -task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function() { +task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function () { cleanTestDirs(); host = "node"; browser = process.env.browser || process.env.b || "IE"; tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light || false; var testConfigFile = 'test.config'; - if(fs.existsSync(testConfigFile)) { + if (fs.existsSync(testConfigFile)) { fs.unlinkSync(testConfigFile); } - if(tests || light) { + if (tests || light) { writeTestConfigFile(tests, light); } @@ -906,7 +908,7 @@ task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFi var cmd = host + " tests/webTestServer.js " + browser + " " + JSON.stringify(tests); console.log(cmd); exec(cmd); -}, {async: true}); +}, { async: true }); function getDiffTool() { var program = process.env['DIFF']; @@ -919,17 +921,17 @@ function getDiffTool() { // Baseline Diff desc("Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable"); task('diff', function () { - var cmd = '"' + getDiffTool() + '" ' + refBaseline + ' ' + localBaseline; + var cmd = '"' + getDiffTool() + '" ' + refBaseline + ' ' + localBaseline; console.log(cmd); exec(cmd); -}, {async: true}); +}, { async: true }); desc("Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable"); task('diff-rwc', function () { - var cmd = '"' + getDiffTool() + '" ' + refRwcBaseline + ' ' + localRwcBaseline; + var cmd = '"' + getDiffTool() + '" ' + refRwcBaseline + ' ' + localRwcBaseline; console.log(cmd); exec(cmd); -}, {async: true}); +}, { async: true }); desc("Builds the test sources and automation in debug mode"); task("tests-debug", ["setDebugMode", "tests"]); @@ -937,30 +939,39 @@ task("tests-debug", ["setDebugMode", "tests"]); // Makes the test results the new baseline desc("Makes the most recent test results the new baseline, overwriting the old baseline"); -task("baseline-accept", function(hardOrSoft) { - var files = jake.readdirR(localBaseline); - var deleteEnding = '.delete'; - for (var i in files) { - if (files[i].substr(files[i].length - deleteEnding.length) === deleteEnding) { - var filename = path.basename(files[i]); - filename = filename.substr(0, filename.length - deleteEnding.length); - fs.unlink(path.join(refBaseline, filename)); - } else { - jake.cpR(files[i], refBaseline); - } - } +task("baseline-accept", function () { + acceptBaseline(""); }); +function acceptBaseline(containerFolder) { + var sourceFolder = path.join(localBaseline, containerFolder); + var targetFolder = path.join(refBaseline, containerFolder); + console.log('Accept baselines from ' + sourceFolder + ' to ' + targetFolder); + var files = fs.readdirSync(sourceFolder); + var deleteEnding = '.delete'; + for (var i in files) { + var filename = files[i]; + if (filename.substr(filename.length - deleteEnding.length) === deleteEnding) { + filename = filename.substr(0, filename.length - deleteEnding.length); + fs.unlinkSync(path.join(targetFolder, filename)); + } else { + var target = path.join(targetFolder, filename); + if (fs.existsSync(target)) { + fs.unlinkSync(target); + } + fs.renameSync(path.join(sourceFolder, filename), target); + } + } +} + desc("Makes the most recent rwc test results the new baseline, overwriting the old baseline"); -task("baseline-accept-rwc", function() { - jake.rmRf(refRwcBaseline); - fs.renameSync(localRwcBaseline, refRwcBaseline); +task("baseline-accept-rwc", function () { + acceptBaseline("rwc"); }); desc("Makes the most recent test262 test results the new baseline, overwriting the old baseline"); -task("baseline-accept-test262", function() { - jake.rmRf(refTest262Baseline); - fs.renameSync(localTest262Baseline, refTest262Baseline); +task("baseline-accept-test262", function () { + acceptBaseline("test262"); }); @@ -970,8 +981,8 @@ var webhostJsPath = "tests/webhost/webtsc.js"; compileFile(webhostJsPath, [webhostPath], [tscFile, webhostPath].concat(libraryTargets), [], /*useBuiltCompiler*/true); desc("Builds the tsc web host"); -task("webhost", [webhostJsPath], function() { - jake.cpR(path.join(builtLocalDirectory, "lib.d.ts"), "tests/webhost/", {silent: true}); +task("webhost", [webhostJsPath], function () { + jake.cpR(path.join(builtLocalDirectory, "lib.d.ts"), "tests/webhost/", { silent: true }); }); // Perf compiler @@ -984,38 +995,38 @@ task("perftsc", [perftscJsPath]); // Instrumented compiler var loggedIOpath = harnessDirectory + 'loggedIO.ts'; var loggedIOJsPath = builtLocalDirectory + 'loggedIO.js'; -file(loggedIOJsPath, [builtLocalDirectory, loggedIOpath], function() { +file(loggedIOJsPath, [builtLocalDirectory, loggedIOpath], function () { var temp = builtLocalDirectory + 'temp'; jake.mkdirP(temp); var options = "--outdir " + temp + ' ' + loggedIOpath; var cmd = host + " " + LKGDirectory + compilerFilename + " " + options + " "; console.log(cmd + "\n"); var ex = jake.createExec([cmd]); - ex.addListener("cmdEnd", function() { + ex.addListener("cmdEnd", function () { fs.renameSync(temp + '/harness/loggedIO.js', loggedIOJsPath); jake.rmRf(temp); complete(); }); ex.run(); -}, {async: true}); +}, { async: true }); var instrumenterPath = harnessDirectory + 'instrumenter.ts'; var instrumenterJsPath = builtLocalDirectory + 'instrumenter.js'; compileFile(instrumenterJsPath, [instrumenterPath], [tscFile, instrumenterPath].concat(libraryTargets), [], /*useBuiltCompiler*/ true); desc("Builds an instrumented tsc.js"); -task('tsc-instrumented', [loggedIOJsPath, instrumenterJsPath, tscFile], function() { +task('tsc-instrumented', [loggedIOJsPath, instrumenterJsPath, tscFile], function () { var cmd = host + ' ' + instrumenterJsPath + ' record iocapture ' + builtLocalDirectory + compilerFilename; console.log(cmd); var ex = jake.createExec([cmd]); - ex.addListener("cmdEnd", function() { + ex.addListener("cmdEnd", function () { complete(); }); ex.run(); }, { async: true }); desc("Updates the sublime plugin's tsserver"); -task("update-sublime", ["local", serverFile], function() { +task("update-sublime", ["local", serverFile], function () { jake.cpR(serverFile, "../TypeScript-Sublime-Plugin/tsserver/"); jake.cpR(serverFile + ".map", "../TypeScript-Sublime-Plugin/tsserver/"); }); @@ -1031,33 +1042,33 @@ var tslintRules = [ "objectLiteralSurroundingSpaceRule", "noTypeAssertionWhitespaceRule" ]; -var tslintRulesFiles = tslintRules.map(function(p) { +var tslintRulesFiles = tslintRules.map(function (p) { return path.join(tslintRuleDir, p + ".ts"); }); -var tslintRulesOutFiles = tslintRules.map(function(p) { +var tslintRulesOutFiles = tslintRules.map(function (p) { return path.join(builtLocalDirectory, "tslint", p + ".js"); }); desc("Compiles tslint rules to js"); task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(["build-rules-end"])); -tslintRulesFiles.forEach(function(ruleFile, i) { +tslintRulesFiles.forEach(function (ruleFile, i) { compileFile(tslintRulesOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false, - { noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint")}); + { noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint") }); }); desc("Emit the start of the build-rules fold"); -task("build-rules-start", [] , function() { +task("build-rules-start", [], function () { if (fold.isTravis()) console.log(fold.start("build-rules")); }); desc("Emit the end of the build-rules fold"); -task("build-rules-end", [] , function() { +task("build-rules-end", [], function () { if (fold.isTravis()) console.log(fold.end("build-rules")); }); var lintTargets = compilerSources .concat(harnessSources) // Other harness sources - .concat(["instrumenter.ts"].map(function(f) { return path.join(harnessDirectory, f) })) + .concat(["instrumenter.ts"].map(function (f) { return path.join(harnessDirectory, f) })) .concat(serverCoreSources) .concat(tslintRulesFiles) .concat(servicesSources) @@ -1068,10 +1079,10 @@ function sendNextFile(files, child, callback, failures) { var file = files.pop(); if (file) { console.log("Linting '" + file + "'."); - child.send({kind: "file", name: file}); + child.send({ kind: "file", name: file }); } else { - child.send({kind: "close"}); + child.send({ kind: "close" }); callback(failures); } } @@ -1079,7 +1090,7 @@ function sendNextFile(files, child, callback, failures) { function spawnLintWorker(files, callback) { var child = child_process.fork("./scripts/parallel-lint"); var failures = 0; - child.on("message", function(data) { + child.on("message", function (data) { switch (data.kind) { case "result": if (data.failures > 0) { @@ -1099,7 +1110,7 @@ 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"], function () { if (fold.isTravis()) console.log(fold.start("lint")); var startTime = mark(); var failed = 0; @@ -1114,7 +1125,7 @@ task("lint", ["build-rules"], function() { var workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length; - var names = Object.keys(done).sort(function(namea, nameb) { + var names = Object.keys(done).sort(function (namea, nameb) { return done[namea] - done[nameb]; }); @@ -1138,4 +1149,4 @@ task("lint", ["build-rules"], function() { } } } -}, {async: true}); +}, { async: true }); From 8ad2744e9a7d0d7eb30286f0b6718b7b5f6cc4f9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 19 Aug 2016 15:44:14 -0700 Subject: [PATCH 27/50] Refactor baseliners out of compiler runner (#10440) --- src/harness/compilerRunner.ts | 222 ++-------------------------------- src/harness/harness.ts | 214 ++++++++++++++++++++++++++++++++ src/harness/rwcRunner.ts | 7 +- 3 files changed, 227 insertions(+), 216 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 88e81ffcf3..a64435b7dd 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -1,8 +1,6 @@ /// /// /// -// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`. -/* tslint:disable:no-null-keyword */ const enum CompilerTestType { Conformance, @@ -136,21 +134,10 @@ class CompilerBaselineRunner extends RunnerBase { otherFiles = undefined; }); - function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string { - return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : ""; - } - - function getErrorBaseline(toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], result: Harness.Compiler.CompilerResult) { - return Harness.Compiler.getErrorBaseline(toBeCompiled.concat(otherFiles), result.errors); - } - // check errors it("Correct errors for " + fileName, () => { if (this.errors) { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), (): string => { - if (result.errors.length === 0) return null; - return getErrorBaseline(toBeCompiled, otherFiles, result); - }); + Harness.Compiler.doErrorBaseline(justName, toBeCompiled.concat(otherFiles), result.errors); } }); @@ -168,8 +155,10 @@ class CompilerBaselineRunner extends RunnerBase { Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => { const record = result.getSourceMapRecord(); if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) { - // Because of the noEmitOnError option no files are created. We need to return null because baselining isn"t required. + // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. + /* tslint:disable:no-null-keyword */ return null; + /* tslint:enable:no-null-keyword */ } return record; }); @@ -178,87 +167,12 @@ class CompilerBaselineRunner extends RunnerBase { it("Correct JS output for " + fileName, () => { if (hasNonDtsFiles && this.emit) { - if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) { - throw new Error("Expected at least one js file to be emitted or at least one error to be created."); - } - - // check js output - Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, ".js"), () => { - let tsCode = ""; - const tsSources = otherFiles.concat(toBeCompiled); - if (tsSources.length > 1) { - tsCode += "//// [" + fileName + "] ////\r\n\r\n"; - } - for (let i = 0; i < tsSources.length; i++) { - tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n"; - tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : ""); - } - - let jsCode = ""; - for (let i = 0; i < result.files.length; i++) { - jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n"; - jsCode += getByteOrderMarkText(result.files[i]); - jsCode += result.files[i].code; - } - - if (result.declFilesCode.length > 0) { - jsCode += "\r\n\r\n"; - for (let i = 0; i < result.declFilesCode.length; i++) { - jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n"; - jsCode += getByteOrderMarkText(result.declFilesCode[i]); - jsCode += result.declFilesCode[i].code; - } - } - - const declFileCompilationResult = - Harness.Compiler.compileDeclarationFiles( - toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined); - - if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) { - jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; - jsCode += "\r\n\r\n"; - jsCode += getErrorBaseline(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles, declFileCompilationResult.declResult); - } - - if (jsCode.length > 0) { - return tsCode + "\r\n\r\n" + jsCode; - } - else { - return null; - } - }); + Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, toBeCompiled, otherFiles, harnessSettings); } }); it("Correct Sourcemap output for " + fileName, () => { - if (options.inlineSourceMap) { - if (result.sourceMaps.length > 0) { - throw new Error("No sourcemap files should be generated if inlineSourceMaps was set."); - } - return null; - } - else if (options.sourceMap) { - if (result.sourceMaps.length !== result.files.length) { - throw new Error("Number of sourcemap files should be same as js files."); - } - - Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, ".js.map"), () => { - if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) { - // We need to return null here or the runBaseLine will actually create a empty file. - // Baselining isn't required here because there is no output. - return null; - } - - let sourceMapCode = ""; - for (let i = 0; i < result.sourceMaps.length; i++) { - sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n"; - sourceMapCode += getByteOrderMarkText(result.sourceMaps[i]); - sourceMapCode += result.sourceMaps[i].code; - } - - return sourceMapCode; - }); - } + Harness.Compiler.doSourcemapBaseline(justName, options, result); }); it("Correct type/symbol baselines for " + fileName, () => { @@ -266,129 +180,7 @@ class CompilerBaselineRunner extends RunnerBase { return; } - // NEWTODO: Type baselines - if (result.errors.length !== 0) { - return; - } - - // The full walker simulates the types that you would get from doing a full - // compile. The pull walker simulates the types you get when you just do - // a type query for a random node (like how the LS would do it). Most of the - // time, these will be the same. However, occasionally, they can be different. - // Specifically, when the compiler internally depends on symbol IDs to order - // things, then we may see different results because symbols can be created in a - // different order with 'pull' operations, and thus can produce slightly differing - // output. - // - // For example, with a full type check, we may see a type displayed as: number | string - // But with a pull type check, we may see it as: string | number - // - // These types are equivalent, but depend on what order the compiler observed - // certain parts of the program. - - const program = result.program; - const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName)); - - const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true); - - const fullResults = ts.createMap(); - const pullResults = ts.createMap(); - - for (const sourceFile of allFiles) { - fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName); - pullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName); - } - - // Produce baselines. The first gives the types for all expressions. - // The second gives symbols for all identifiers. - let e1: Error, e2: Error; - try { - checkBaseLines(/*isSymbolBaseLine*/ false); - } - catch (e) { - e1 = e; - } - - try { - checkBaseLines(/*isSymbolBaseLine*/ true); - } - catch (e) { - e2 = e; - } - - if (e1 || e2) { - throw e1 || e2; - } - - return; - - function checkBaseLines(isSymbolBaseLine: boolean) { - const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine); - const pullBaseLine = generateBaseLine(pullResults, isSymbolBaseLine); - - const fullExtension = isSymbolBaseLine ? ".symbols" : ".types"; - const pullExtension = isSymbolBaseLine ? ".symbols.pull" : ".types.pull"; - - if (fullBaseLine !== pullBaseLine) { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); - Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine); - } - else { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); - } - } - - function generateBaseLine(typeWriterResults: ts.Map, isSymbolBaseline: boolean): string { - const typeLines: string[] = []; - const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {}; - - allFiles.forEach(file => { - const codeLines = file.content.split("\n"); - typeWriterResults[file.unitName].forEach(result => { - if (isSymbolBaseline && !result.symbol) { - return; - } - - const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type; - const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString; - if (!typeMap[file.unitName]) { - typeMap[file.unitName] = {}; - } - - let typeInfo = [formattedLine]; - const existingTypeInfo = typeMap[file.unitName][result.line]; - if (existingTypeInfo) { - typeInfo = existingTypeInfo.concat(typeInfo); - } - typeMap[file.unitName][result.line] = typeInfo; - }); - - typeLines.push("=== " + file.unitName + " ===\r\n"); - for (let i = 0; i < codeLines.length; i++) { - const currentCodeLine = codeLines[i]; - typeLines.push(currentCodeLine + "\r\n"); - if (typeMap[file.unitName]) { - const typeInfo = typeMap[file.unitName][i]; - if (typeInfo) { - typeInfo.forEach(ty => { - typeLines.push(">" + ty + "\r\n"); - }); - if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) { - } - else { - typeLines.push("\r\n"); - } - } - } - else { - typeLines.push("No type information for this code."); - } - } - }); - - return typeLines.join(""); - } - + Harness.Compiler.doTypeAndSymbolBaseline(justName, result, toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName))); }); }); } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 3375b8e47e..14cb3147c3 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1328,6 +1328,220 @@ namespace Harness { Harness.IO.newLine() + Harness.IO.newLine() + outputLines.join("\r\n"); } + export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) { + Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string => { + if (errors.length === 0) { + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + return getErrorBaseline(inputFiles, errors); + }); + } + + export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[]) { + if (result.errors.length !== 0) { + return; + } + // The full walker simulates the types that you would get from doing a full + // compile. The pull walker simulates the types you get when you just do + // a type query for a random node (like how the LS would do it). Most of the + // time, these will be the same. However, occasionally, they can be different. + // Specifically, when the compiler internally depends on symbol IDs to order + // things, then we may see different results because symbols can be created in a + // different order with 'pull' operations, and thus can produce slightly differing + // output. + // + // For example, with a full type check, we may see a type displayed as: number | string + // But with a pull type check, we may see it as: string | number + // + // These types are equivalent, but depend on what order the compiler observed + // certain parts of the program. + + const program = result.program; + + const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true); + + const fullResults = ts.createMap(); + + for (const sourceFile of allFiles) { + fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName); + } + + // Produce baselines. The first gives the types for all expressions. + // The second gives symbols for all identifiers. + let e1: Error, e2: Error; + try { + checkBaseLines(/*isSymbolBaseLine*/ false); + } + catch (e) { + e1 = e; + } + + try { + checkBaseLines(/*isSymbolBaseLine*/ true); + } + catch (e) { + e2 = e; + } + + if (e1 || e2) { + throw e1 || e2; + } + + return; + + function checkBaseLines(isSymbolBaseLine: boolean) { + const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine); + + const fullExtension = isSymbolBaseLine ? ".symbols" : ".types"; + + Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, fullExtension), () => fullBaseLine); + } + + function generateBaseLine(typeWriterResults: ts.Map, isSymbolBaseline: boolean): string { + const typeLines: string[] = []; + const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {}; + + allFiles.forEach(file => { + const codeLines = file.content.split("\n"); + typeWriterResults[file.unitName].forEach(result => { + if (isSymbolBaseline && !result.symbol) { + return; + } + + const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type; + const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString; + if (!typeMap[file.unitName]) { + typeMap[file.unitName] = {}; + } + + let typeInfo = [formattedLine]; + const existingTypeInfo = typeMap[file.unitName][result.line]; + if (existingTypeInfo) { + typeInfo = existingTypeInfo.concat(typeInfo); + } + typeMap[file.unitName][result.line] = typeInfo; + }); + + typeLines.push("=== " + file.unitName + " ===\r\n"); + for (let i = 0; i < codeLines.length; i++) { + const currentCodeLine = codeLines[i]; + typeLines.push(currentCodeLine + "\r\n"); + if (typeMap[file.unitName]) { + const typeInfo = typeMap[file.unitName][i]; + if (typeInfo) { + typeInfo.forEach(ty => { + typeLines.push(">" + ty + "\r\n"); + }); + if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) { + } + else { + typeLines.push("\r\n"); + } + } + } + else { + typeLines.push("No type information for this code."); + } + } + }); + + return typeLines.join(""); + } + } + + function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string { + return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : ""; + } + + export function doSourcemapBaseline(baselinePath: string, options: ts.CompilerOptions, result: CompilerResult) { + if (options.inlineSourceMap) { + if (result.sourceMaps.length > 0) { + throw new Error("No sourcemap files should be generated if inlineSourceMaps was set."); + } + return; + } + else if (options.sourceMap) { + if (result.sourceMaps.length !== result.files.length) { + throw new Error("Number of sourcemap files should be same as js files."); + } + + Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js.map"), () => { + if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) { + // We need to return null here or the runBaseLine will actually create a empty file. + // Baselining isn't required here because there is no output. + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + + let sourceMapCode = ""; + for (let i = 0; i < result.sourceMaps.length; i++) { + sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n"; + sourceMapCode += getByteOrderMarkText(result.sourceMaps[i]); + sourceMapCode += result.sourceMaps[i].code; + } + + return sourceMapCode; + }); + } + } + + export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) { + if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) { + throw new Error("Expected at least one js file to be emitted or at least one error to be created."); + } + + // check js output + Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js"), () => { + let tsCode = ""; + const tsSources = otherFiles.concat(toBeCompiled); + if (tsSources.length > 1) { + tsCode += "//// [" + header + "] ////\r\n\r\n"; + } + for (let i = 0; i < tsSources.length; i++) { + tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n"; + tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : ""); + } + + let jsCode = ""; + for (let i = 0; i < result.files.length; i++) { + jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n"; + jsCode += getByteOrderMarkText(result.files[i]); + jsCode += result.files[i].code; + } + + if (result.declFilesCode.length > 0) { + jsCode += "\r\n\r\n"; + for (let i = 0; i < result.declFilesCode.length; i++) { + jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n"; + jsCode += getByteOrderMarkText(result.declFilesCode[i]); + jsCode += result.declFilesCode[i].code; + } + } + + const declFileCompilationResult = + Harness.Compiler.compileDeclarationFiles( + toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined); + + if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) { + jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; + jsCode += "\r\n\r\n"; + jsCode += Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors); + } + + if (jsCode.length > 0) { + return tsCode + "\r\n\r\n" + jsCode; + } + else { + /* tslint:disable:no-null-keyword */ + return null; + /* tslint:enable:no-null-keyword */ + } + }); + } + export function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): string { // Collect, test, and sort the fileNames outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName))); diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 17346016fb..5720f9b541 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -222,7 +222,12 @@ namespace RWC { } }); - // TODO: Type baselines (need to refactor out from compilerRunner) + it("has the expected types", () => { + Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles + .concat(otherFiles) + .filter(file => !!compilerResult.program.getSourceFile(file.unitName)) + .filter(e => !Harness.isDefaultLibraryFile(e.unitName))); + }); }); } } From 057357be88319368da2e1380da93915075ed05fc Mon Sep 17 00:00:00 2001 From: zhengbli Date: Fri, 19 Aug 2016 15:48:46 -0700 Subject: [PATCH 28/50] CR feedback --- src/services/services.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 64b872d14a..94b69113da 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4913,22 +4913,24 @@ namespace ts { if (!documentation) { documentation = symbol.getDocumentationComment(); - if ((!documentation || documentation.length === 0) && symbol.flags & SymbolFlags.Property) { + if (documentation.length === 0 && symbol.flags & SymbolFlags.Property) { // For some special property access expressions like `experts.foo = foo` or `module.exports.foo = foo` // there documentation comments might be attached to the right hand side symbol of their declarations. // The pattern of such special property access is that the parent symbol is the symbol of the file. if (symbol.parent && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) { - forEach(symbol.declarations, declaration => { - if (declaration.parent && declaration.parent.kind === SyntaxKind.BinaryExpression) { - const rhsSymbol = program.getTypeChecker().getSymbolAtLocation((declaration.parent).right); - if (rhsSymbol) { - documentation = rhsSymbol.getDocumentationComment(); - if (documentation && documentation.length > 0) { - return true; - } + for(const declaration of symbol.declarations) { + if (!declaration.parent || declaration.parent.kind !== SyntaxKind.BinaryExpression) { + continue; + } + + const rhsSymbol = program.getTypeChecker().getSymbolAtLocation((declaration.parent).right); + if (rhsSymbol) { + documentation = rhsSymbol.getDocumentationComment(); + if (documentation.length > 0) { + return; } } - }); + } } } } From a5bb13f6c1b5020c61d681432f33d5f3f939c941 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Fri, 19 Aug 2016 16:53:36 -0700 Subject: [PATCH 29/50] fix broken tests --- src/services/services.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 94b69113da..c59551457b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4918,17 +4918,19 @@ namespace ts { // there documentation comments might be attached to the right hand side symbol of their declarations. // The pattern of such special property access is that the parent symbol is the symbol of the file. if (symbol.parent && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) { - for(const declaration of symbol.declarations) { + for (const declaration of symbol.declarations) { if (!declaration.parent || declaration.parent.kind !== SyntaxKind.BinaryExpression) { continue; } const rhsSymbol = program.getTypeChecker().getSymbolAtLocation((declaration.parent).right); - if (rhsSymbol) { - documentation = rhsSymbol.getDocumentationComment(); - if (documentation.length > 0) { - return; - } + if (!rhsSymbol) { + continue; + } + + documentation = rhsSymbol.getDocumentationComment(); + if (documentation.length > 0) { + break; } } } From a531b87b3c668f56a4140699f89b7fcc4160dfbc Mon Sep 17 00:00:00 2001 From: Yui Date: Fri, 19 Aug 2016 17:06:05 -0700 Subject: [PATCH 30/50] Pass in baselineOpts into types baselines so that RWC baselines can be written to internal folder (#10443) --- src/harness/harness.ts | 4 ++-- src/harness/rwcRunner.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 14cb3147c3..9e27f500b8 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1339,7 +1339,7 @@ namespace Harness { }); } - export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[]) { + export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions) { if (result.errors.length !== 0) { return; } @@ -1396,7 +1396,7 @@ namespace Harness { const fullExtension = isSymbolBaseLine ? ".symbols" : ".types"; - Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, fullExtension), () => fullBaseLine); + Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, fullExtension), () => fullBaseLine, opts); } function generateBaseLine(typeWriterResults: ts.Map, isSymbolBaseline: boolean): string { diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 5720f9b541..d56e8d6d35 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -226,7 +226,7 @@ namespace RWC { Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles .concat(otherFiles) .filter(file => !!compilerResult.program.getSourceFile(file.unitName)) - .filter(e => !Harness.isDefaultLibraryFile(e.unitName))); + .filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts); }); }); } From eeec775da0f3dabe9c73254c02b5254bab84c882 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Sat, 20 Aug 2016 19:12:11 -0700 Subject: [PATCH 31/50] Add more test for 10426 --- .../completionEntryDetailAcrossFiles02.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/cases/fourslash/server/completionEntryDetailAcrossFiles02.ts diff --git a/tests/cases/fourslash/server/completionEntryDetailAcrossFiles02.ts b/tests/cases/fourslash/server/completionEntryDetailAcrossFiles02.ts new file mode 100644 index 0000000000..2c5e53ea22 --- /dev/null +++ b/tests/cases/fourslash/server/completionEntryDetailAcrossFiles02.ts @@ -0,0 +1,20 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: a.js +//// /** +//// * Modify the parameter +//// * @param {string} p1 +//// */ +//// var foo = function (p1) { } +//// module.exports.foo = foo; +//// fo/*1*/ + +// @Filename: b.ts +//// import a = require("./a"); +//// a.fo/*2*/ + +goTo.marker('1'); +verify.completionEntryDetailIs("foo", "var foo: (p1: string) => void", "Modify the parameter"); +goTo.marker('2'); +verify.completionEntryDetailIs("foo", "(property) a.foo: (p1: string) => void", "Modify the parameter"); From 794d3e91d07021409ef4a985dd90fc431f4f04c5 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Sat, 20 Aug 2016 20:35:58 -0700 Subject: [PATCH 32/50] routine update of dom libs --- src/lib/dom.generated.d.ts | 70 +++++++++++++++++++++++++------- src/lib/webworker.generated.d.ts | 2 +- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index d2938f6e98..ee657f64a6 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -126,6 +126,7 @@ interface KeyAlgorithm { } interface KeyboardEventInit extends EventModifierInit { + code?: string; key?: string; location?: number; repeat?: boolean; @@ -2288,7 +2289,7 @@ declare var DeviceRotationRate: { new(): DeviceRotationRate; } -interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEvent { +interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEvent, ParentNode { /** * Sets or gets the URL for the current document. */ @@ -3351,7 +3352,7 @@ declare var Document: { new(): Document; } -interface DocumentFragment extends Node, NodeSelector { +interface DocumentFragment extends Node, NodeSelector, ParentNode { addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; } @@ -3420,7 +3421,7 @@ declare var EXT_texture_filter_anisotropic: { readonly TEXTURE_MAX_ANISOTROPY_EXT: number; } -interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelector, ChildNode { +interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelector, ChildNode, ParentNode { readonly classList: DOMTokenList; className: string; readonly clientHeight: number; @@ -3675,6 +3676,16 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec getElementsByClassName(classNames: string): NodeListOf; matches(selector: string): boolean; closest(selector: string): Element | null; + scrollIntoView(arg?: boolean | ScrollIntoViewOptions): void; + scroll(options?: ScrollToOptions): void; + scroll(x: number, y: number): void; + scrollTo(options?: ScrollToOptions): void; + scrollTo(x: number, y: number): void; + scrollBy(options?: ScrollToOptions): void; + scrollBy(x: number, y: number): void; + insertAdjacentElement(position: string, insertedElement: Element): Element | null; + insertAdjacentHTML(where: string, html: string): void; + insertAdjacentText(where: string, text: string): void; addEventListener(type: "MSGestureChange", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void; addEventListener(type: "MSGestureDoubleTap", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void; addEventListener(type: "MSGestureEnd", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void; @@ -4446,7 +4457,7 @@ interface HTMLCanvasElement extends HTMLElement { * @param type The standard MIME type for the image format to return. If you do not specify this parameter, the default value is a PNG format image. */ toDataURL(type?: string, ...args: any[]): string; - toBlob(callback: (result: Blob | null) => void, ... arguments: any[]): void; + toBlob(callback: (result: Blob | null) => void, type?: string, ...arguments: any[]): void; } declare var HTMLCanvasElement: { @@ -4621,11 +4632,7 @@ interface HTMLElement extends Element { click(): void; dragDrop(): boolean; focus(): void; - insertAdjacentElement(position: string, insertedElement: Element): Element; - insertAdjacentHTML(where: string, html: string): void; - insertAdjacentText(where: string, text: string): void; msGetInputContext(): MSInputMethodContext; - scrollIntoView(top?: boolean): void; setActive(): void; addEventListener(type: "MSContentZoom", listener: (this: this, ev: UIEvent) => any, useCapture?: boolean): void; addEventListener(type: "MSGestureChange", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void; @@ -5890,6 +5897,7 @@ interface HTMLLinkElement extends HTMLElement, LinkStyle { */ type: string; import?: Document; + integrity: string; addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; } @@ -6178,7 +6186,7 @@ interface HTMLMediaElement extends HTMLElement { */ canPlayType(type: string): string; /** - * Fires immediately after the client loads the object. + * Resets the audio or video object and loads a new media resource. */ load(): void; /** @@ -6751,6 +6759,7 @@ interface HTMLScriptElement extends HTMLElement { * Sets or retrieves the MIME type for the associated scripting engine. */ type: string; + integrity: string; } declare var HTMLScriptElement: { @@ -7756,6 +7765,7 @@ interface KeyboardEvent extends UIEvent { readonly repeat: boolean; readonly shiftKey: boolean; readonly which: number; + readonly code: string; getModifierState(keyArg: string): boolean; initKeyboardEvent(typeArg: string, canBubbleArg: boolean, cancelableArg: boolean, viewArg: Window, keyArg: string, locationArg: number, modifiersListArg: string, repeat: boolean, locale: string): void; readonly DOM_KEY_LOCATION_JOYSTICK: number; @@ -9128,6 +9138,7 @@ interface PerformanceTiming { readonly responseStart: number; readonly unloadEventEnd: number; readonly unloadEventStart: number; + readonly secureConnectionStart: number; toJSON(): any; } @@ -11405,8 +11416,8 @@ declare var StereoPannerNode: { interface Storage { readonly length: number; clear(): void; - getItem(key: string): string; - key(index: number): string; + getItem(key: string): string | null; + key(index: number): string | null; removeItem(key: string): void; setItem(key: string, data: string): void; [key: string]: any; @@ -12947,7 +12958,7 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window onunload: (this: this, ev: Event) => any; onvolumechange: (this: this, ev: Event) => any; onwaiting: (this: this, ev: Event) => any; - readonly opener: Window; + opener: any; orientation: string | number; readonly outerHeight: number; readonly outerWidth: number; @@ -13002,6 +13013,9 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window webkitConvertPointFromNodeToPage(node: Node, pt: WebKitPoint): WebKitPoint; webkitConvertPointFromPageToNode(node: Node, pt: WebKitPoint): WebKitPoint; webkitRequestAnimationFrame(callback: FrameRequestCallback): number; + scroll(options?: ScrollToOptions): void; + scrollTo(options?: ScrollToOptions): void; + scrollBy(options?: ScrollToOptions): void; addEventListener(type: "MSGestureChange", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void; addEventListener(type: "MSGestureDoubleTap", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void; addEventListener(type: "MSGestureEnd", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void; @@ -14029,6 +14043,20 @@ interface ProgressEventInit extends EventInit { total?: number; } +interface ScrollOptions { + behavior?: ScrollBehavior; +} + +interface ScrollToOptions extends ScrollOptions { + left?: number; + top?: number; +} + +interface ScrollIntoViewOptions extends ScrollOptions { + block?: ScrollLogicalPosition; + inline?: ScrollLogicalPosition; +} + interface ClipboardEventInit extends EventInit { data?: string; dataType?: string; @@ -14072,7 +14100,7 @@ interface EcdsaParams extends Algorithm { } interface EcKeyGenParams extends Algorithm { - typedCurve: string; + namedCurve: string; } interface EcKeyAlgorithm extends KeyAlgorithm { @@ -14208,6 +14236,13 @@ interface JsonWebKey { k?: string; } +interface ParentNode { + readonly children: HTMLCollection; + readonly firstElementChild: Element; + readonly lastElementChild: Element; + readonly childElementCount: number; +} + declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject; interface ErrorEventHandler { @@ -14278,7 +14313,7 @@ declare var location: Location; declare var locationbar: BarProp; declare var menubar: BarProp; declare var msCredentials: MSCredentials; -declare var name: string; +declare const name: never; declare var navigator: Navigator; declare var offscreenBuffering: string | boolean; declare var onabort: (this: Window, ev: UIEvent) => any; @@ -14372,7 +14407,7 @@ declare var ontouchstart: (ev: TouchEvent) => any; declare var onunload: (this: Window, ev: Event) => any; declare var onvolumechange: (this: Window, ev: Event) => any; declare var onwaiting: (this: Window, ev: Event) => any; -declare var opener: Window; +declare var opener: any; declare var orientation: string | number; declare var outerHeight: number; declare var outerWidth: number; @@ -14425,6 +14460,9 @@ declare function webkitCancelAnimationFrame(handle: number): void; declare function webkitConvertPointFromNodeToPage(node: Node, pt: WebKitPoint): WebKitPoint; declare function webkitConvertPointFromPageToNode(node: Node, pt: WebKitPoint): WebKitPoint; declare function webkitRequestAnimationFrame(callback: FrameRequestCallback): number; +declare function scroll(options?: ScrollToOptions): void; +declare function scrollTo(options?: ScrollToOptions): void; +declare function scrollBy(options?: ScrollToOptions): void; declare function toString(): string; declare function addEventListener(type: string, listener?: EventListenerOrEventListenerObject, useCapture?: boolean): void; declare function dispatchEvent(evt: Event): boolean; @@ -14580,6 +14618,8 @@ type MSOutboundPayload = MSVideoSendPayload | MSAudioSendPayload; type RTCIceGatherCandidate = RTCIceCandidate | RTCIceCandidateComplete; type RTCTransport = RTCDtlsTransport | RTCSrtpSdesTransport; type payloadtype = number; +type ScrollBehavior = "auto" | "instant" | "smooth"; +type ScrollLogicalPosition = "start" | "center" | "end" | "nearest"; type IDBValidKey = number | string | Date | IDBArrayKey; type BufferSource = ArrayBuffer | ArrayBufferView; type MouseWheelEvent = WheelEvent; \ No newline at end of file diff --git a/src/lib/webworker.generated.d.ts b/src/lib/webworker.generated.d.ts index c61a1a8b8a..483348f3f7 100644 --- a/src/lib/webworker.generated.d.ts +++ b/src/lib/webworker.generated.d.ts @@ -1000,7 +1000,7 @@ interface EcdsaParams extends Algorithm { } interface EcKeyGenParams extends Algorithm { - typedCurve: string; + namedCurve: string; } interface EcKeyAlgorithm extends KeyAlgorithm { From e445e012c4fe9a3673204988491266a41d56fd7a Mon Sep 17 00:00:00 2001 From: zhengbli Date: Sat, 20 Aug 2016 20:41:33 -0700 Subject: [PATCH 33/50] Add test for jsdoc syntactic classification for function declaration --- .../syntacticClassificationsDocComment4.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/cases/fourslash/syntacticClassificationsDocComment4.ts diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment4.ts b/tests/cases/fourslash/syntacticClassificationsDocComment4.ts new file mode 100644 index 0000000000..d8ac2f12d8 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsDocComment4.ts @@ -0,0 +1,24 @@ +/// + +//// /** @param {number} p1 */ +//// function foo(p1) {} + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/** "), + c.punctuation("@"), + c.docCommentTagName("param"), + c.comment(" "), + c.punctuation("{"), + c.keyword("number"), + c.punctuation("}"), + c.comment(" "), + c.parameterName("p1"), + c.comment(" */"), + c.keyword("function"), + c.identifier("foo"), + c.punctuation("("), + c.parameterName("p1"), + c.punctuation(")"), + c.punctuation("{"), + c.punctuation("}")); From 6d2323b0d81bc85e33bb0bce8b292938d8a0de27 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Sat, 20 Aug 2016 20:41:47 -0700 Subject: [PATCH 34/50] Simplify implementation --- src/compiler/utilities.ts | 4 ++++ src/services/services.ts | 37 ++++++++++++------------------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0a1f43203c..f1573f9b58 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -301,6 +301,10 @@ namespace ts { return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode; } + export function isJSDocTag(node: Node) { + return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode; + } + export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { if (nodeIsMissing(node) || !node.decorators) { return getTokenPosOfNode(node, sourceFile); diff --git a/src/services/services.ts b/src/services/services.ts index c4b42f9422..22f5a74eb5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -21,7 +21,6 @@ namespace ts { getChildCount(sourceFile?: SourceFile): number; getChildAt(index: number, sourceFile?: SourceFile): Node; getChildren(sourceFile?: SourceFile): Node[]; - getNonJsDocCommentChildren?(sourceFile?: SourceFile): Node[]; getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number; getFullStart(): number; getEnd(): number; @@ -197,7 +196,6 @@ namespace ts { public parent: Node; public jsDocComments: JSDocComment[]; private _children: Node[]; - private _nonJsDocCommentChildren: Node[]; constructor(kind: SyntaxKind, pos: number, end: number) { this.pos = pos; @@ -275,22 +273,20 @@ namespace ts { } private createChildren(sourceFile?: SourceFile) { - let jsDocCommentChildren: Node[]; - let nonJsDocCommentChildren: Node[]; + let children: Node[]; if (this.kind >= SyntaxKind.FirstNode) { scanner.setText((sourceFile || this.getSourceFile()).text); - jsDocCommentChildren = []; - nonJsDocCommentChildren = []; + children = []; let pos = this.pos; const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode; - const processNode = (node: Node, children = nonJsDocCommentChildren) => { + const processNode = (node: Node) => { if (pos < node.pos) { pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner); } children.push(node); pos = node.end; }; - const processNodes = (nodes: NodeArray, children = nonJsDocCommentChildren) => { + const processNodes = (nodes: NodeArray) => { if (pos < nodes.pos) { pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner); } @@ -300,7 +296,7 @@ namespace ts { // jsDocComments need to be the first children if (this.jsDocComments) { for (const jsDocComment of this.jsDocComments) { - processNode(jsDocComment, jsDocCommentChildren); + processNode(jsDocComment); } } // For syntactic classifications, all trivia are classcified together, including jsdoc comments. @@ -309,12 +305,11 @@ namespace ts { pos = this.pos; forEachChild(this, processNode, processNodes); if (pos < this.end) { - this.addSyntheticNodes(nonJsDocCommentChildren, pos, this.end); + this.addSyntheticNodes(children, pos, this.end); } scanner.setText(undefined); } - this._nonJsDocCommentChildren = nonJsDocCommentChildren || emptyArray; - this._children = concatenate(jsDocCommentChildren, this._nonJsDocCommentChildren); + this._children = children || emptyArray; } public getChildCount(sourceFile?: SourceFile): number { @@ -332,18 +327,6 @@ namespace ts { return this._children; } - public getNonJsDocCommentChildren(sourceFile?: SourceFile): Node[] { - // If the cached children were cleared, that means some node before the current node has changed. - // so even if we have a cached nonJsDocCommentChildren, it would be outdated as well. - if (!this._children) { - this.createChildren(sourceFile); - } - // If the node has cached children but not nonJsDocCommentChildren, it means the children is not created - // via calling the "createChildren" method, so it can only be a SyntaxList. As SyntaxList cannot have jsDocCommentChildren - // anyways, we can just return its children. - return this._nonJsDocCommentChildren ? this._nonJsDocCommentChildren : this._children; - } - public getFirstToken(sourceFile?: SourceFile): Node { const children = this.getChildren(sourceFile); if (!children.length) { @@ -7591,6 +7574,10 @@ namespace ts { * False will mean that node is not classified and traverse routine should recurse into node contents. */ function tryClassifyNode(node: Node): boolean { + if (isJSDocTag(node)) { + return true; + } + if (nodeIsMissing(node)) { return true; } @@ -7746,7 +7733,7 @@ namespace ts { if (decodedTextSpanIntersectsWith(spanStart, spanLength, element.pos, element.getFullWidth())) { checkForClassificationCancellation(element.kind); - const children = element.getNonJsDocCommentChildren ? element.getNonJsDocCommentChildren(sourceFile) : element.getChildren(sourceFile); + const children = element.getChildren(sourceFile); for (let i = 0, n = children.length; i < n; i++) { const child = children[i]; if (!tryClassifyNode(child)) { From 84386f9d3b4ac8309ab5f3ce936613f14cad9106 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Sat, 20 Aug 2016 20:46:56 -0700 Subject: [PATCH 35/50] Tolerate certain errors in tsconfig.json --- src/server/editorServices.ts | 50 +++++++++++++++++++++--------------- src/server/session.ts | 20 ++++++++++----- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index db9bdd5043..0d84fa54a4 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -603,8 +603,11 @@ namespace ts.server { return projects.length > 1 ? deduplicate(result, areEqual) : result; } + export type ProjectServiceEvent = + { eventName: "context", data: { project: Project, fileName: string } } | { eventName: "configFileDiag", data: { triggerFile?: string, configFileName: string, diagnostics: Diagnostic[] } } + export interface ProjectServiceEventHandler { - (eventName: string, project: Project, fileName: string): void; + (event: ProjectServiceEvent): void; } export interface HostConfiguration { @@ -748,10 +751,13 @@ namespace ts.server { return ts.normalizePath(name); } - watchedProjectConfigFileChanged(project: Project) { + watchedProjectConfigFileChanged(project: Project): void { this.log("Config file changed: " + project.projectFilename); - this.updateConfiguredProject(project); + const configFileErrors = this.updateConfiguredProject(project); this.updateProjectStructure(); + if (configFileErrors && configFileErrors.length > 0) { + this.eventHandler({ eventName: "configFileDiag", data: { triggerFile: project.projectFilename, configFileName: project.projectFilename, diagnostics: configFileErrors } }); + } } log(msg: string, type = "Err") { @@ -828,13 +834,13 @@ namespace ts.server { for (let j = 0, flen = this.openFileRoots.length; j < flen; j++) { const openFile = this.openFileRoots[j]; if (this.eventHandler) { - this.eventHandler("context", openFile.defaultProject, openFile.fileName); + this.eventHandler({ eventName: "context", data: { project: openFile.defaultProject, fileName: openFile.fileName } }); } } for (let j = 0, flen = this.openFilesReferenced.length; j < flen; j++) { const openFile = this.openFilesReferenced[j]; if (this.eventHandler) { - this.eventHandler("context", openFile.defaultProject, openFile.fileName); + this.eventHandler({ eventName: "context", data: { project: openFile.defaultProject, fileName: openFile.fileName } }); } } } @@ -1234,11 +1240,12 @@ namespace ts.server { else { this.updateConfiguredProject(project); } + return { configFileName }; } else { this.log("No config files found."); } - return configFileName ? { configFileName } : {}; + return {}; } /** @@ -1328,7 +1335,7 @@ namespace ts.server { return undefined; } - configFileToProjectOptions(configFilename: string): { succeeded: boolean, projectOptions?: ProjectOptions, errors?: Diagnostic[] } { + configFileToProjectOptions(configFilename: string): { succeeded: boolean, projectOptions?: ProjectOptions, errors: Diagnostic[] } { configFilename = ts.normalizePath(configFilename); // file references will be relative to dirPath (or absolute) const dirPath = ts.getDirectoryPath(configFilename); @@ -1341,20 +1348,19 @@ namespace ts.server { const parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath, /*existingOptions*/ {}, configFilename); Debug.assert(!!parsedCommandLine.fileNames); - if (parsedCommandLine.errors && (parsedCommandLine.errors.length > 0)) { - return { succeeded: false, errors: parsedCommandLine.errors }; - } - else if (parsedCommandLine.fileNames.length === 0) { + if (parsedCommandLine.fileNames.length === 0) { const error = createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename); - return { succeeded: false, errors: [error] }; + return { succeeded: false, errors: concatenate(parsedCommandLine.errors, [error]) }; } else { + // if the project has some files, we can continue with the parsed options and tolerate + // errors in the parsedCommandLine const projectOptions: ProjectOptions = { files: parsedCommandLine.fileNames, wildcardDirectories: parsedCommandLine.wildcardDirectories, compilerOptions: parsedCommandLine.options, }; - return { succeeded: true, projectOptions }; + return { succeeded: true, projectOptions, errors: parsedCommandLine.errors }; } } } @@ -1377,10 +1383,11 @@ namespace ts.server { return false; } - openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors?: Diagnostic[] } { - const { succeeded, projectOptions, errors } = this.configFileToProjectOptions(configFilename); + openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors: Diagnostic[] } { + const { succeeded, projectOptions, errors: errorsFromConfigFile } = this.configFileToProjectOptions(configFilename); + // Note: even if "succeeded"" is true, "errors" may still exist, as they are just tolerated if (!succeeded) { - return { success: false, errors }; + return { success: false, errors: errorsFromConfigFile }; } else { if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) { @@ -1392,7 +1399,7 @@ namespace ts.server { project.projectFileWatcher = this.host.watchFile( toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), _ => this.watchedProjectConfigFileChanged(project)); - return { success: true, project }; + return { success: true, project, errors: errorsFromConfigFile }; } } @@ -1433,7 +1440,7 @@ namespace ts.server { return watchers; }, >{}); - return { success: true, project: project, errors }; + return { success: true, project: project, errors: concatenate(errors, errorsFromConfigFile) }; } } @@ -1451,7 +1458,7 @@ namespace ts.server { if (projectOptions.compilerOptions && !projectOptions.compilerOptions.disableSizeLimit && this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) { project.setProjectOptions(projectOptions); if (project.languageServiceDiabled) { - return; + return errors; } project.disableLanguageService(); @@ -1459,7 +1466,7 @@ namespace ts.server { project.directoryWatcher.close(); project.directoryWatcher = undefined; } - return; + return errors; } if (project.languageServiceDiabled) { @@ -1478,7 +1485,7 @@ namespace ts.server { } } project.finishGraph(); - return; + return errors; } // if the project is too large, the root files might not have been all loaded if the total @@ -1524,6 +1531,7 @@ namespace ts.server { project.setProjectOptions(projectOptions); project.finishGraph(); } + return errors; } } diff --git a/src/server/session.ts b/src/server/session.ts index 9383a54bd4..00468330ff 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -153,16 +153,22 @@ namespace ts.server { private logger: Logger ) { this.projectService = - new ProjectService(host, logger, (eventName, project, fileName) => { - this.handleEvent(eventName, project, fileName); + new ProjectService(host, logger, event => { + this.handleEvent(event); }); } - private handleEvent(eventName: string, project: Project, fileName: string) { - if (eventName == "context") { - this.projectService.log("got context event, updating diagnostics for" + fileName, "Info"); - this.updateErrorCheck([{ fileName, project }], this.changeSeq, - (n) => n === this.changeSeq, 100); + private handleEvent(event: ProjectServiceEvent) { + switch (event.eventName) { + case "context": + const { project, fileName } = event.data; + this.projectService.log("got context event, updating diagnostics for" + fileName, "Info"); + this.updateErrorCheck([{ fileName, project }], this.changeSeq, + (n) => n === this.changeSeq, 100); + break; + case "configFileDiag": + const { triggerFile, configFileName, diagnostics } = event.data; + this.configFileDiagnosticEvent(triggerFile, configFileName, diagnostics); } } From b2074172e1ef7b6f389d398e737268c16dc2cd93 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Sat, 20 Aug 2016 20:47:30 -0700 Subject: [PATCH 36/50] Add test for configFile error tolerance --- src/harness/unittests/tsserverProjectSystem.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 49f033b9de..d4ed84191b 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -623,5 +623,23 @@ namespace ts { checkNumberOfConfiguredProjects(projectService, 1); checkNumberOfInferredProjects(projectService, 0); }); + + it("should tolerate config file errors and still try to build a project", () => { + const configFile: FileOrFolder = { + path: "/a/b/tsconfig.json", + content: `{ + "compilerOptions": { + "target": "es6", + "allowAnything": true + }, + "someOtherProperty": {} + }` + }; + const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, libFile, configFile]); + const projectService = new server.ProjectService(host, nullLogger); + projectService.openClientFile(commonFile1.path); + checkNumberOfConfiguredProjects(projectService, 1); + checkConfiguredProjectRootFiles(projectService.configuredProjects[0], [commonFile1.path, commonFile2.path]); + }); }); } \ No newline at end of file From a8ab52fd573dd28e1ee8a19f6271e6e98b35dd64 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Sat, 20 Aug 2016 20:47:35 -0700 Subject: [PATCH 37/50] Use TS parser to tolerate more errors in tsconfig.json --- src/harness/unittests/tsconfigParsing.ts | 20 +++ src/server/editorServices.ts | 173 ++++++++++++----------- src/services/utilities.ts | 20 +++ 3 files changed, 132 insertions(+), 81 deletions(-) diff --git a/src/harness/unittests/tsconfigParsing.ts b/src/harness/unittests/tsconfigParsing.ts index 557379dff3..2c9bcdb842 100644 --- a/src/harness/unittests/tsconfigParsing.ts +++ b/src/harness/unittests/tsconfigParsing.ts @@ -181,5 +181,25 @@ namespace ts { ["/d.ts", "/folder/e.ts"] ); }); + + it("parse and re-emit tsconfig.json file with diagnostics", () => { + const content = `{ + "compilerOptions": { + "allowJs": true + "outDir": "bin" + } + "files": ["file1.ts"] + }`; + const { configJsonObject, diagnostics } = parseAndReEmitConfigJSONFile(content); + const expectedResult = { + compilerOptions: { + allowJs: true, + outDir: "bin" + }, + files: ["file1.ts"] + }; + assert.isTrue(diagnostics.length === 2); + assert.equal(JSON.stringify(configJsonObject), JSON.stringify(expectedResult)); + }); }); } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 0d84fa54a4..255ad8547e 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -702,7 +702,8 @@ namespace ts.server { } handleProjectFileListChanges(project: Project) { - const { projectOptions } = this.configFileToProjectOptions(project.projectFilename); + const { projectOptions, errors } = this.configFileToProjectOptions(project.projectFilename); + this.reportConfigFileDiagnostics(project.projectFilename, errors); const newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f))); const currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f))); @@ -720,18 +721,32 @@ namespace ts.server { } } + reportConfigFileDiagnostics(configFileName: string, diagnostics: Diagnostic[], triggerFile?: string) { + if (diagnostics && diagnostics.length > 0) { + this.eventHandler({ + eventName: "configFileDiag", + data: { configFileName, diagnostics, triggerFile } + }); + } + } + /** * This is the callback function when a watched directory has an added tsconfig file. */ directoryWatchedForTsconfigChanged(fileName: string) { - if (ts.getBaseFileName(fileName) != "tsconfig.json") { + if (ts.getBaseFileName(fileName) !== "tsconfig.json") { this.log(fileName + " is not tsconfig.json"); return; } this.log("Detected newly added tsconfig file: " + fileName); - const { projectOptions } = this.configFileToProjectOptions(fileName); + const { projectOptions, errors } = this.configFileToProjectOptions(fileName); + this.reportConfigFileDiagnostics(fileName, errors); + + if (!projectOptions) { + return; + } const rootFilesInTsconfig = projectOptions.files.map(f => this.getCanonicalFileName(f)); const openFileRoots = this.openFileRoots.map(s => this.getCanonicalFileName(s.fileName)); @@ -1224,7 +1239,7 @@ namespace ts.server { const project = this.findConfiguredProjectByConfigFile(configFileName); if (!project) { const configResult = this.openConfigFile(configFileName, fileName); - if (!configResult.success) { + if (!configResult.project) { return { configFileName, configFileErrors: configResult.errors }; } else { @@ -1335,33 +1350,31 @@ namespace ts.server { return undefined; } - configFileToProjectOptions(configFilename: string): { succeeded: boolean, projectOptions?: ProjectOptions, errors: Diagnostic[] } { + configFileToProjectOptions(configFilename: string): { projectOptions?: ProjectOptions, errors: Diagnostic[] } { configFilename = ts.normalizePath(configFilename); + let errors: Diagnostic[] = []; // file references will be relative to dirPath (or absolute) const dirPath = ts.getDirectoryPath(configFilename); const contents = this.host.readFile(configFilename); - const rawConfig: { config?: ProjectOptions; error?: Diagnostic; } = ts.parseConfigFileTextToJson(configFilename, contents); - if (rawConfig.error) { - return { succeeded: false, errors: [rawConfig.error] }; + const { configJsonObject, diagnostics } = ts.parseAndReEmitConfigJSONFile(contents); + errors = concatenate(errors, diagnostics); + const parsedCommandLine = ts.parseJsonConfigFileContent(configJsonObject, this.host, dirPath, /*existingOptions*/ {}, configFilename); + errors = concatenate(errors, parsedCommandLine.errors); + Debug.assert(!!parsedCommandLine.fileNames); + + if (parsedCommandLine.fileNames.length === 0) { + errors.push(createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename)); + return { errors }; } else { - const parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath, /*existingOptions*/ {}, configFilename); - Debug.assert(!!parsedCommandLine.fileNames); - - if (parsedCommandLine.fileNames.length === 0) { - const error = createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename); - return { succeeded: false, errors: concatenate(parsedCommandLine.errors, [error]) }; - } - else { - // if the project has some files, we can continue with the parsed options and tolerate - // errors in the parsedCommandLine - const projectOptions: ProjectOptions = { - files: parsedCommandLine.fileNames, - wildcardDirectories: parsedCommandLine.wildcardDirectories, - compilerOptions: parsedCommandLine.options, - }; - return { succeeded: true, projectOptions, errors: parsedCommandLine.errors }; - } + // if the project has some files, we can continue with the parsed options and tolerate + // errors in the parsedCommandLine + const projectOptions: ProjectOptions = { + files: parsedCommandLine.fileNames, + wildcardDirectories: parsedCommandLine.wildcardDirectories, + compilerOptions: parsedCommandLine.options, + }; + return { projectOptions, errors }; } } @@ -1383,65 +1396,63 @@ namespace ts.server { return false; } - openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors: Diagnostic[] } { - const { succeeded, projectOptions, errors: errorsFromConfigFile } = this.configFileToProjectOptions(configFilename); - // Note: even if "succeeded"" is true, "errors" may still exist, as they are just tolerated - if (!succeeded) { - return { success: false, errors: errorsFromConfigFile }; + openConfigFile(configFilename: string, clientFileName?: string): { project?: Project, errors: Diagnostic[] } { + const parseConfigFileResult = this.configFileToProjectOptions(configFilename); + let errors = parseConfigFileResult.errors; + if (!parseConfigFileResult.projectOptions) { + return { errors }; } - else { - if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) { - if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) { - const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true); + const projectOptions = parseConfigFileResult.projectOptions; + if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) { + if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) { + const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true); - // for configured projects with languageService disabled, we only watch its config file, - // do not care about the directory changes in the folder. - project.projectFileWatcher = this.host.watchFile( - toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), - _ => this.watchedProjectConfigFileChanged(project)); - return { success: true, project, errors: errorsFromConfigFile }; - } + // for configured projects with languageService disabled, we only watch its config file, + // do not care about the directory changes in the folder. + project.projectFileWatcher = this.host.watchFile( + toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), + _ => this.watchedProjectConfigFileChanged(project)); + return { project, errors }; + } + } + + const project = this.createProject(configFilename, projectOptions); + for (const rootFilename of projectOptions.files) { + if (this.host.fileExists(rootFilename)) { + const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename); + project.addRoot(info); + } + else { + (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename)); + } + } + project.finishGraph(); + project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project)); + + const configDirectoryPath = ts.getDirectoryPath(configFilename); + + this.log("Add recursive watcher for: " + configDirectoryPath); + project.directoryWatcher = this.host.watchDirectory( + configDirectoryPath, + path => this.directoryWatchedForSourceFilesChanged(project, path), + /*recursive*/ true + ); + + project.directoriesWatchedForWildcards = reduceProperties(createMap(projectOptions.wildcardDirectories), (watchers, flag, directory) => { + if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) { + const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0; + this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`); + watchers[directory] = this.host.watchDirectory( + directory, + path => this.directoryWatchedForSourceFilesChanged(project, path), + recursive + ); } - const project = this.createProject(configFilename, projectOptions); - let errors: Diagnostic[]; - for (const rootFilename of projectOptions.files) { - if (this.host.fileExists(rootFilename)) { - const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename); - project.addRoot(info); - } - else { - (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename)); - } - } - project.finishGraph(); - project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project)); + return watchers; + }, >{}); - const configDirectoryPath = ts.getDirectoryPath(configFilename); - - this.log("Add recursive watcher for: " + configDirectoryPath); - project.directoryWatcher = this.host.watchDirectory( - configDirectoryPath, - path => this.directoryWatchedForSourceFilesChanged(project, path), - /*recursive*/ true - ); - - project.directoriesWatchedForWildcards = reduceProperties(createMap(projectOptions.wildcardDirectories), (watchers, flag, directory) => { - if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) { - const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0; - this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`); - watchers[directory] = this.host.watchDirectory( - directory, - path => this.directoryWatchedForSourceFilesChanged(project, path), - recursive - ); - } - - return watchers; - }, >{}); - - return { success: true, project: project, errors: concatenate(errors, errorsFromConfigFile) }; - } + return { project: project, errors }; } updateConfiguredProject(project: Project): Diagnostic[] { @@ -1450,8 +1461,8 @@ namespace ts.server { this.removeProject(project); } else { - const { succeeded, projectOptions, errors } = this.configFileToProjectOptions(project.projectFilename); - if (!succeeded) { + const { projectOptions, errors } = this.configFileToProjectOptions(project.projectFilename); + if (!projectOptions) { return errors; } else { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 7f41cdbb3a..858f889bc6 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -925,4 +925,24 @@ namespace ts { } return ensureScriptKind(fileName, scriptKind); } + + export function parseAndReEmitConfigJSONFile(content: string) { + const options: TranspileOptions = { + fileName: "config.js", + compilerOptions: { + target: ScriptTarget.ES6 + }, + reportDiagnostics: true + }; + const { outputText, diagnostics } = ts.transpileModule("(" + content + ")", options); + // Becasue the content was wrapped in "()", the start position of diagnostics needs to be subtract by 1 + // also, the emitted result will have "(" in the beginning and ");" in the end. We need to strip these + // as well + const trimmedOutput = outputText.trim(); + const configJsonObject = JSON.parse(trimmedOutput.substring(1, trimmedOutput.length - 2)); + for (const diagnostic of diagnostics) { + diagnostic.start = diagnostic.start - 1; + } + return { configJsonObject, diagnostics }; + } } \ No newline at end of file From 582d8b8fc8047fcda47024a37bf5258d2050fe3b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 21 Aug 2016 16:18:45 -0700 Subject: [PATCH 38/50] Implement tuple types as type references to synthesized generic types --- src/compiler/checker.ts | 177 +++++++++++++++++++--------------------- src/compiler/types.ts | 5 +- 2 files changed, 87 insertions(+), 95 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8568cd5fee..d87dbd1696 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -106,7 +106,7 @@ namespace ts { isOptionalParameter }; - const tupleTypes = createMap(); + const tupleTypes: TupleType[] = []; const unionTypes = createMap(); const intersectionTypes = createMap(); const stringLiteralTypes = createMap(); @@ -2145,9 +2145,6 @@ namespace ts { // The specified symbol flags need to be reinterpreted as type flags buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); } - else if (type.flags & TypeFlags.Tuple) { - writeTupleType(type); - } else if (!(flags & TypeFormatFlags.InTypeAlias) && type.flags & (TypeFlags.Anonymous | TypeFlags.UnionOrIntersection) && type.aliasSymbol) { const typeArguments = type.aliasTypeArguments; writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); @@ -2214,6 +2211,11 @@ namespace ts { writePunctuation(writer, SyntaxKind.OpenBracketToken); writePunctuation(writer, SyntaxKind.CloseBracketToken); } + else if (type.target.flags & TypeFlags.Tuple) { + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writeTypeList(type.typeArguments.slice(0, type.target.typeParameters.length), SyntaxKind.CommaToken); + writePunctuation(writer, SyntaxKind.CloseBracketToken); + } else { // Write the type reference in the format f.g.C where A and B are type arguments // for outer type parameters, and f and g are the respective declaring containers of those @@ -2242,12 +2244,6 @@ namespace ts { } } - function writeTupleType(type: TupleType) { - writePunctuation(writer, SyntaxKind.OpenBracketToken); - writeTypeList(type.elementTypes, SyntaxKind.CommaToken); - writePunctuation(writer, SyntaxKind.CloseBracketToken); - } - function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); @@ -2958,7 +2954,7 @@ namespace ts { : elementType; if (!type) { if (isTupleType(parentType)) { - error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), (parentType).elementTypes.length, pattern.elements.length); + error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), getTypeReferenceArity(parentType), pattern.elements.length); } else { error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName); @@ -3150,12 +3146,12 @@ namespace ts { } // If the pattern has at least one element, and no rest element, then it should imply a tuple type. const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); + let result = createTupleType(elementTypes); if (includePatternInType) { - const result = createNewTupleType(elementTypes); + result = cloneTypeReference(result); result.pattern = pattern; - return result; } - return createTupleType(elementTypes); + return result; } // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself @@ -3564,18 +3560,19 @@ namespace ts { } function getBaseTypes(type: InterfaceType): ObjectType[] { - const isClass = type.symbol.flags & SymbolFlags.Class; - const isInterface = type.symbol.flags & SymbolFlags.Interface; if (!type.resolvedBaseTypes) { - if (!isClass && !isInterface) { - Debug.fail("type must be class or interface"); + if (type.flags & TypeFlags.Tuple) { + type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters))]; } - if (isClass) { + else if (type.symbol.flags & SymbolFlags.Class) { resolveBaseTypesOfClass(type); } - if (isInterface) { + else if (type.symbol.flags & SymbolFlags.Interface) { resolveBaseTypesOfInterface(type); } + else { + Debug.fail("type must be class or interface"); + } } return type.resolvedBaseTypes; } @@ -4001,20 +3998,25 @@ namespace ts { return createTypeReference((type).target, concatenate((type).typeArguments, [thisArgument || (type).target.thisType])); } - if (type.flags & TypeFlags.Tuple) { - return createTupleType((type as TupleType).elementTypes, thisArgument); - } return type; } function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) { - let mapper = identityMapper; - let members = source.symbol.members; - let callSignatures = source.declaredCallSignatures; - let constructSignatures = source.declaredConstructSignatures; - let stringIndexInfo = source.declaredStringIndexInfo; - let numberIndexInfo = source.declaredNumberIndexInfo; - if (!rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) { + let mapper: TypeMapper; + let members: SymbolTable; + let callSignatures: Signature[]; + let constructSignatures: Signature[]; + let stringIndexInfo: IndexInfo; + let numberIndexInfo: IndexInfo; + if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) { + mapper = identityMapper; + members = source.symbol ? source.symbol.members : createSymbolTable(source.declaredProperties); + callSignatures = source.declaredCallSignatures; + constructSignatures = source.declaredConstructSignatures; + stringIndexInfo = source.declaredStringIndexInfo; + numberIndexInfo = source.declaredNumberIndexInfo; + } + else { mapper = createTypeMapper(typeParameters, typeArguments); members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1); callSignatures = instantiateList(source.declaredCallSignatures, mapper, instantiateSignature); @@ -4024,7 +4026,7 @@ namespace ts { } const baseTypes = getBaseTypes(source); if (baseTypes.length) { - if (members === source.symbol.members) { + if (source.symbol && members === source.symbol.members) { members = createSymbolTable(source.declaredProperties); } const thisArgument = lastOrUndefined(typeArguments); @@ -4094,26 +4096,6 @@ namespace ts { return result; } - function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable { - const members = createMap(); - for (let i = 0; i < memberTypes.length; i++) { - const symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i); - symbol.type = memberTypes[i]; - members[i] = symbol; - } - return members; - } - - function resolveTupleTypeMembers(type: TupleType) { - const arrayElementType = getUnionType(type.elementTypes); - // Make the tuple type itself the 'this' type by including an extra type argument - // (Unless it's provided in the case that the tuple is a type parameter constraint) - const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type.thisType || type])); - const members = createTupleTypeMemberSymbols(type.elementTypes); - addInheritedMembers(members, arrayType.properties); - setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo); - } - function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature { for (const s of signatureList) { if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, compareTypesIdentical)) { @@ -4292,9 +4274,6 @@ namespace ts { else if (type.flags & TypeFlags.Anonymous) { resolveAnonymousTypeMembers(type); } - else if (type.flags & TypeFlags.Tuple) { - resolveTupleTypeMembers(type); - } else if (type.flags & TypeFlags.Union) { resolveUnionTypeMembers(type); } @@ -4992,6 +4971,13 @@ namespace ts { return type; } + function cloneTypeReference(source: TypeReference): TypeReference { + let type = createObjectType(source.flags, source.symbol); + type.target = source.target; + type.typeArguments = source.typeArguments; + return type; + } + // Get type from reference to class or interface function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type { const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); @@ -5234,17 +5220,44 @@ namespace ts { return links.resolvedType; } - function createTupleType(elementTypes: Type[], thisType?: Type) { - const id = getTypeListId(elementTypes) + "," + (thisType ? thisType.id : 0); - return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes, thisType)); + function createTupleTypeOfArity(arity: number): TupleType { + const typeParameters: TypeParameter[] = []; + const properties: Symbol[] = []; + for (let i = 0; i < arity; i++) { + const typeParameter = createType(TypeFlags.TypeParameter); + typeParameters.push(typeParameter); + const property = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i); + property.type = typeParameter; + properties.push(property); + } + const type = createObjectType(TypeFlags.Tuple | TypeFlags.Reference); + type.typeParameters = typeParameters; + type.outerTypeParameters = undefined; + type.localTypeParameters = typeParameters; + type.instantiations = createMap(); + type.instantiations[getTypeListId(type.typeParameters)] = type; + type.target = type; + type.typeArguments = type.typeParameters; + type.thisType = createType(TypeFlags.TypeParameter | TypeFlags.ThisType); + type.thisType.constraint = type; + type.declaredProperties = properties; + type.declaredCallSignatures = emptyArray; + type.declaredConstructSignatures = emptyArray; + type.declaredStringIndexInfo = undefined; + type.declaredNumberIndexInfo = undefined; + return type; } - function createNewTupleType(elementTypes: Type[], thisType?: Type) { - const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0); - const type = createObjectType(TypeFlags.Tuple | propagatedFlags); - type.elementTypes = elementTypes; - type.thisType = thisType; - return type; + function getTupleTypeOfArity(arity: number): TupleType { + return tupleTypes[arity] || (tupleTypes[arity] = createTupleTypeOfArity(arity)); + } + + function getTypeReferenceArity(type: TypeReference): number { + return type.target.typeParameters.length; + } + + function createTupleType(elementTypes: Type[]) { + return createTypeReference(getTupleTypeOfArity(elementTypes.length), elementTypes); } function getTypeFromTupleTypeNode(node: TupleTypeNode): Type { @@ -5845,9 +5858,6 @@ namespace ts { if (type.flags & TypeFlags.Reference) { return createTypeReference((type).target, instantiateList((type).typeArguments, mapper, instantiateType)); } - if (type.flags & TypeFlags.Tuple) { - return createTupleType(instantiateList((type).elementTypes, mapper, instantiateType)); - } if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) { return getUnionType(instantiateList((type).types, mapper, instantiateType), /*subtypeReduction*/ false, type.aliasSymbol, mapper.targetTypes); } @@ -7168,8 +7178,8 @@ namespace ts { * Check if a Type was written as a tuple type literal. * Prefer using isTupleLikeType() unless the use of `elementTypes` is required. */ - function isTupleType(type: Type): type is TupleType { - return !!(type.flags & TypeFlags.Tuple); + function isTupleType(type: Type): boolean { + return !!(type.flags & TypeFlags.Reference && (type).target.flags & TypeFlags.Tuple); } function getFalsyFlagsOfTypes(types: Type[]): TypeFlags { @@ -7301,11 +7311,8 @@ namespace ts { if (type.flags & TypeFlags.Union) { return getUnionType(map((type).types, getWidenedConstituentType)); } - if (isArrayType(type)) { - return createArrayType(getWidenedType((type).typeArguments[0])); - } - if (isTupleType(type)) { - return createTupleType(map(type.elementTypes, getWidenedType)); + if (isArrayType(type) || isTupleType(type)) { + return createTypeReference((type).target, map((type).typeArguments, getWidenedType)); } } return type; @@ -7331,11 +7338,8 @@ namespace ts { } } } - if (isArrayType(type)) { - return reportWideningErrorsInType((type).typeArguments[0]); - } - if (isTupleType(type)) { - for (const t of type.elementTypes) { + if (isArrayType(type) || isTupleType(type)) { + for (const t of (type).typeArguments) { if (reportWideningErrorsInType(t)) { errorReported = true; } @@ -7445,7 +7449,6 @@ namespace ts { function couldContainTypeParameters(type: Type): boolean { return !!(type.flags & TypeFlags.TypeParameter || type.flags & TypeFlags.Reference && forEach((type).typeArguments, couldContainTypeParameters) || - type.flags & TypeFlags.Tuple && forEach((type).elementTypes, couldContainTypeParameters) || type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); } @@ -7548,14 +7551,6 @@ namespace ts { inferFromTypes(sourceTypes[i], targetTypes[i]); } } - else if (source.flags & TypeFlags.Tuple && target.flags & TypeFlags.Tuple && (source).elementTypes.length === (target).elementTypes.length) { - // If source and target are tuples of the same size, infer from element types - const sourceTypes = (source).elementTypes; - const targetTypes = (target).elementTypes; - for (let i = 0; i < sourceTypes.length; i++) { - inferFromTypes(sourceTypes[i], targetTypes[i]); - } - } else if (target.flags & TypeFlags.UnionOrIntersection) { const targetTypes = (target).types; let typeParameterCount = 0; @@ -9913,7 +9908,7 @@ namespace ts { // If array literal is actually a destructuring pattern, mark it as an implied type. We do this such // that we get the same behavior for "var [x, y] = []" and "[x, y] = []". if (inDestructuringPattern && elementTypes.length) { - const type = createNewTupleType(elementTypes); + const type = cloneTypeReference(createTupleType(elementTypes)); type.pattern = node; return type; } @@ -9927,7 +9922,7 @@ namespace ts { for (let i = elementTypes.length; i < patternElements.length; i++) { const patternElement = patternElements[i]; if (hasDefaultValue(patternElement)) { - elementTypes.push((contextualType).elementTypes[i]); + elementTypes.push((contextualType).typeArguments[i]); } else { if (patternElement.kind !== SyntaxKind.OmittedExpression) { @@ -13038,7 +13033,7 @@ namespace ts { // such as NodeCheckFlags.LexicalThis on "this"expression. checkExpression(element); if (isTupleType(sourceType)) { - error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), (sourceType).elementTypes.length, elements.length); + error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), getTypeReferenceArity(sourceType), elements.length); } else { error(element, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); @@ -18515,7 +18510,7 @@ namespace ts { else if (isTypeOfKind(type, TypeFlags.StringLike)) { return TypeReferenceSerializationKind.StringLikeType; } - else if (isTypeOfKind(type, TypeFlags.Tuple)) { + else if (isTupleType(type)) { return TypeReferenceSerializationKind.ArrayLikeType; } else if (isTypeOfKind(type, TypeFlags.ESSymbol)) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7594d2c3fb..f5d71d0935 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2385,10 +2385,7 @@ namespace ts { instantiations: Map; // Generic instantiation cache } - export interface TupleType extends ObjectType { - elementTypes: Type[]; // Element types - thisType?: Type; // This-type of tuple (only needed for tuples that are constraints of type parameters) - } + export interface TupleType extends GenericType { } export interface UnionOrIntersectionType extends Type { types: Type[]; // Constituent types From 7d82c22bc376d230e5c896aeeadf2ac922c058ca Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 21 Aug 2016 16:53:34 -0700 Subject: [PATCH 39/50] Add comments + minor changes --- src/compiler/checker.ts | 25 ++++++++++++++++--------- src/compiler/types.ts | 4 +--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d87dbd1696..9efaf72c03 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -106,7 +106,7 @@ namespace ts { isOptionalParameter }; - const tupleTypes: TupleType[] = []; + const tupleTypes: GenericType[] = []; const unionTypes = createMap(); const intersectionTypes = createMap(); const stringLiteralTypes = createMap(); @@ -2213,7 +2213,7 @@ namespace ts { } else if (type.target.flags & TypeFlags.Tuple) { writePunctuation(writer, SyntaxKind.OpenBracketToken); - writeTypeList(type.typeArguments.slice(0, type.target.typeParameters.length), SyntaxKind.CommaToken); + writeTypeList(type.typeArguments.slice(0, getTypeReferenceArity(type)), SyntaxKind.CommaToken); writePunctuation(writer, SyntaxKind.CloseBracketToken); } else { @@ -4978,6 +4978,10 @@ namespace ts { return type; } + function getTypeReferenceArity(type: TypeReference): number { + return type.target.typeParameters.length; + } + // Get type from reference to class or interface function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type { const type = getDeclaredTypeOfSymbol(getMergedSymbol(symbol)); @@ -5220,7 +5224,14 @@ namespace ts { return links.resolvedType; } - function createTupleTypeOfArity(arity: number): TupleType { + // We represent tuple types as type references to synthesized generic interface types created by + // this function. The types are of the form: + // + // interface Tuple extends Array { 0: T0, 1: T1, 2: T2, ... } + // + // Note that the generic type created by this function has no symbol associated with it. The same + // is true for each of the synthesized type parameters. + function createTupleTypeOfArity(arity: number): GenericType { const typeParameters: TypeParameter[] = []; const properties: Symbol[] = []; for (let i = 0; i < arity; i++) { @@ -5230,7 +5241,7 @@ namespace ts { property.type = typeParameter; properties.push(property); } - const type = createObjectType(TypeFlags.Tuple | TypeFlags.Reference); + const type = createObjectType(TypeFlags.Tuple | TypeFlags.Reference); type.typeParameters = typeParameters; type.outerTypeParameters = undefined; type.localTypeParameters = typeParameters; @@ -5248,14 +5259,10 @@ namespace ts { return type; } - function getTupleTypeOfArity(arity: number): TupleType { + function getTupleTypeOfArity(arity: number): GenericType { return tupleTypes[arity] || (tupleTypes[arity] = createTupleTypeOfArity(arity)); } - function getTypeReferenceArity(type: TypeReference): number { - return type.target.typeParameters.length; - } - function createTupleType(elementTypes: Type[]) { return createTypeReference(getTupleTypeOfArity(elementTypes.length), elementTypes); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f5d71d0935..656f155784 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2263,7 +2263,7 @@ namespace ts { Class = 1 << 15, // Class Interface = 1 << 16, // Interface Reference = 1 << 17, // Generic type reference - Tuple = 1 << 18, // Tuple + Tuple = 1 << 18, // Synthesized generic tuple type Union = 1 << 19, // Union (T | U) Intersection = 1 << 20, // Intersection (T & U) Anonymous = 1 << 21, // Anonymous @@ -2385,8 +2385,6 @@ namespace ts { instantiations: Map; // Generic instantiation cache } - export interface TupleType extends GenericType { } - export interface UnionOrIntersectionType extends Type { types: Type[]; // Constituent types /* @internal */ From 2e8d11e9c09e8ffb20ff8d8a69399f652fddc510 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 21 Aug 2016 17:01:07 -0700 Subject: [PATCH 40/50] Accept new baselines --- .../arityAndOrderCompatibility01.errors.txt | 6 ++--- .../reference/arrayLiterals3.errors.txt | 6 ++--- .../reference/castingTuple.errors.txt | 16 +++++-------- .../contextualTypeWithTuple.errors.txt | 20 +++++++--------- ...TypedBindingInitializerNegative.errors.txt | 6 ++--- .../declarationsAndAssignments.errors.txt | 16 +++++-------- ...rayBindingPatternAndAssignment2.errors.txt | 6 ++--- ...tructuringParameterDeclaration2.errors.txt | 24 +++++++------------ ...structuringParameterProperties2.errors.txt | 6 ++--- ...structuringParameterProperties5.errors.txt | 10 ++++---- ...structuringVariableDeclaration2.errors.txt | 18 +++++--------- .../genericCallWithTupleType.errors.txt | 12 ++++------ .../iterableArrayPattern29.errors.txt | 6 ++--- .../optionalBindingParameters1.errors.txt | 6 ++--- ...alBindingParametersInOverloads1.errors.txt | 6 ++--- .../baselines/reference/tupleTypes.errors.txt | 18 +++++--------- 16 files changed, 64 insertions(+), 118 deletions(-) diff --git a/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt b/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt index d60f0b7d03..a6a685069d 100644 --- a/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt +++ b/tests/baselines/reference/arityAndOrderCompatibility01.errors.txt @@ -39,8 +39,7 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(26,5): error tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(27,5): error TS2322: Type '{ 0: string; 1: number; }' is not assignable to type '[string]'. Property 'length' is missing in type '{ 0: string; 1: number; }'. tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(28,5): error TS2322: Type '[string, number]' is not assignable to type '[number, string]'. - Types of property '0' are incompatible. - Type 'string' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(29,5): error TS2322: Type 'StrNum' is not assignable to type '[number, string]'. Types of property '0' are incompatible. Type 'string' is not assignable to type 'number'. @@ -136,8 +135,7 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error var n1: [number, string] = x; ~~ !!! error TS2322: Type '[string, number]' is not assignable to type '[number, string]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type 'string' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. var n2: [number, string] = y; ~~ !!! error TS2322: Type 'StrNum' is not assignable to type '[number, string]'. diff --git a/tests/baselines/reference/arrayLiterals3.errors.txt b/tests/baselines/reference/arrayLiterals3.errors.txt index 8e6c7eccf8..f221fd96fa 100644 --- a/tests/baselines/reference/arrayLiterals3.errors.txt +++ b/tests/baselines/reference/arrayLiterals3.errors.txt @@ -1,8 +1,7 @@ tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(10,5): error TS2322: Type 'undefined[]' is not assignable to type '[any, any, any]'. Property '0' is missing in type 'undefined[]'. tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(11,5): error TS2322: Type '[string, number, boolean]' is not assignable to type '[boolean, string, number]'. - Types of property '0' are incompatible. - Type 'string' is not assignable to type 'boolean'. + Type 'string' is not assignable to type 'boolean'. tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(17,5): error TS2322: Type '[number, number, string, boolean]' is not assignable to type '[number, number]'. Types of property 'pop' are incompatible. Type '() => string | number | boolean' is not assignable to type '() => number'. @@ -37,8 +36,7 @@ tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(34,5): error var a1: [boolean, string, number] = ["string", 1, true]; // Error ~~ !!! error TS2322: Type '[string, number, boolean]' is not assignable to type '[boolean, string, number]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type 'string' is not assignable to type 'boolean'. +!!! error TS2322: Type 'string' is not assignable to type 'boolean'. // The resulting type an array literal expression is determined as follows: // - If the array literal contains no spread elements and is an array assignment pattern in a destructuring assignment (section 4.17.1), diff --git a/tests/baselines/reference/castingTuple.errors.txt b/tests/baselines/reference/castingTuple.errors.txt index 6d5549c6bf..2f9eeedf9e 100644 --- a/tests/baselines/reference/castingTuple.errors.txt +++ b/tests/baselines/reference/castingTuple.errors.txt @@ -1,10 +1,8 @@ tests/cases/conformance/types/tuple/castingTuple.ts(28,10): error TS2352: Type '[number, string]' cannot be converted to type '[number, number]'. - Types of property '1' are incompatible. - Type 'string' is not comparable to type 'number'. + Type 'string' is not comparable to type 'number'. tests/cases/conformance/types/tuple/castingTuple.ts(29,10): error TS2352: Type '[C, D]' cannot be converted to type '[A, I]'. - Types of property '0' are incompatible. - Type 'C' is not comparable to type 'A'. - Property 'a' is missing in type 'C'. + Type 'C' is not comparable to type 'A'. + Property 'a' is missing in type 'C'. tests/cases/conformance/types/tuple/castingTuple.ts(30,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'array1' must be of type '{}[]', but here has type 'number[]'. tests/cases/conformance/types/tuple/castingTuple.ts(31,1): error TS2304: Cannot find name 't4'. @@ -40,14 +38,12 @@ tests/cases/conformance/types/tuple/castingTuple.ts(31,1): error TS2304: Cannot var t3 = <[number, number]>numStrTuple; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Type '[number, string]' cannot be converted to type '[number, number]'. -!!! error TS2352: Types of property '1' are incompatible. -!!! error TS2352: Type 'string' is not comparable to type 'number'. +!!! error TS2352: Type 'string' is not comparable to type 'number'. var t9 = <[A, I]>classCDTuple; ~~~~~~~~~~~~~~~~~~~~ !!! error TS2352: Type '[C, D]' cannot be converted to type '[A, I]'. -!!! error TS2352: Types of property '0' are incompatible. -!!! error TS2352: Type 'C' is not comparable to type 'A'. -!!! error TS2352: Property 'a' is missing in type 'C'. +!!! error TS2352: Type 'C' is not comparable to type 'A'. +!!! error TS2352: Property 'a' is missing in type 'C'. var array1 = numStrTuple; ~~~~~~ !!! error TS2403: Subsequent variable declarations must have the same type. Variable 'array1' must be of type '{}[]', but here has type 'number[]'. diff --git a/tests/baselines/reference/contextualTypeWithTuple.errors.txt b/tests/baselines/reference/contextualTypeWithTuple.errors.txt index e0580ca237..a488d8c764 100644 --- a/tests/baselines/reference/contextualTypeWithTuple.errors.txt +++ b/tests/baselines/reference/contextualTypeWithTuple.errors.txt @@ -5,9 +5,8 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(3,5): error TS232 Type 'true' is not assignable to type 'string | number'. tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(15,1): error TS2322: Type '[number, string, boolean]' is not assignable to type '[number, string]'. tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(18,1): error TS2322: Type '[{}, number]' is not assignable to type '[{ a: string; }, number]'. - Types of property '0' are incompatible. - Type '{}' is not assignable to type '{ a: string; }'. - Property 'a' is missing in type '{}'. + Type '{}' is not assignable to type '{ a: string; }'. + Property 'a' is missing in type '{}'. tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(19,1): error TS2322: Type '[number, string]' is not assignable to type '[number, string, boolean]'. Property '2' is missing in type '[number, string]'. tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(20,5): error TS2322: Type '[string, string, number]' is not assignable to type '[string, string]'. @@ -18,9 +17,8 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(20,5): error TS23 tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(24,1): error TS2322: Type '[C, string | number]' is not assignable to type '[C, string | number, D]'. Property '2' is missing in type '[C, string | number]'. tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(25,1): error TS2322: Type '[number, string | number]' is not assignable to type '[number, string]'. - Types of property '1' are incompatible. - Type 'string | number' is not assignable to type 'string'. - Type 'number' is not assignable to type 'string'. + Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. ==== tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts (7 errors) ==== @@ -52,9 +50,8 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(25,1): error TS23 objNumTuple = [ {}, 5]; ~~~~~~~~~~~ !!! error TS2322: Type '[{}, number]' is not assignable to type '[{ a: string; }, number]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type '{}' is not assignable to type '{ a: string; }'. -!!! error TS2322: Property 'a' is missing in type '{}'. +!!! error TS2322: Type '{}' is not assignable to type '{ a: string; }'. +!!! error TS2322: Property 'a' is missing in type '{}'. numStrBoolTuple = numStrTuple; ~~~~~~~~~~~~~~~ !!! error TS2322: Type '[number, string]' is not assignable to type '[number, string, boolean]'. @@ -76,6 +73,5 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(25,1): error TS23 numStrTuple = unionTuple3; ~~~~~~~~~~~ !!! error TS2322: Type '[number, string | number]' is not assignable to type '[number, string]'. -!!! error TS2322: Types of property '1' are incompatible. -!!! error TS2322: Type 'string | number' is not assignable to type 'string'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. \ No newline at end of file +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. \ No newline at end of file diff --git a/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt b/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt index 42d617887e..447ccec5dd 100644 --- a/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt +++ b/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt @@ -11,8 +11,7 @@ tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTyp tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(16,23): error TS2322: Type '(arg: string) => number' is not assignable to type '(s: string) => string'. Type 'number' is not assignable to type 'string'. tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(21,14): error TS2322: Type '[number, number]' is not assignable to type '[string, number]'. - Types of property '0' are incompatible. - Type 'number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(26,14): error TS2322: Type '"baz"' is not assignable to type '"foo" | "bar"'. @@ -57,8 +56,7 @@ tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTyp function g({ prop = [101, 1234] }: Tuples) {} ~~~~ !!! error TS2322: Type '[number, number]' is not assignable to type '[string, number]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. interface StringUnion { prop: "foo" | "bar"; diff --git a/tests/baselines/reference/declarationsAndAssignments.errors.txt b/tests/baselines/reference/declarationsAndAssignments.errors.txt index 517eaafe4a..3ed9e241c3 100644 --- a/tests/baselines/reference/declarationsAndAssignments.errors.txt +++ b/tests/baselines/reference/declarationsAndAssignments.errors.txt @@ -18,11 +18,9 @@ tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(73,14): tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(74,11): error TS2459: Type 'undefined[]' has no property 'a' and no string index signature. tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(74,14): error TS2459: Type 'undefined[]' has no property 'b' and no string index signature. tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(106,5): error TS2345: Argument of type '[number, [string, { y: boolean; }]]' is not assignable to parameter of type '[number, [string, { x: any; y?: boolean; }]]'. - Types of property '1' are incompatible. - Type '[string, { y: boolean; }]' is not assignable to type '[string, { x: any; y?: boolean; }]'. - Types of property '1' are incompatible. - Type '{ y: boolean; }' is not assignable to type '{ x: any; y?: boolean; }'. - Property 'x' is missing in type '{ y: boolean; }'. + Type '[string, { y: boolean; }]' is not assignable to type '[string, { x: any; y?: boolean; }]'. + Type '{ y: boolean; }' is not assignable to type '{ x: any; y?: boolean; }'. + Property 'x' is missing in type '{ y: boolean; }'. tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,6): error TS2322: Type 'string' is not assignable to type 'number'. tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,9): error TS2322: Type 'number' is not assignable to type 'string'. @@ -174,11 +172,9 @@ tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,9): f14([2, ["abc", { y: false }]]); // Error, no x ~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '[number, [string, { y: boolean; }]]' is not assignable to parameter of type '[number, [string, { x: any; y?: boolean; }]]'. -!!! error TS2345: Types of property '1' are incompatible. -!!! error TS2345: Type '[string, { y: boolean; }]' is not assignable to type '[string, { x: any; y?: boolean; }]'. -!!! error TS2345: Types of property '1' are incompatible. -!!! error TS2345: Type '{ y: boolean; }' is not assignable to type '{ x: any; y?: boolean; }'. -!!! error TS2345: Property 'x' is missing in type '{ y: boolean; }'. +!!! error TS2345: Type '[string, { y: boolean; }]' is not assignable to type '[string, { x: any; y?: boolean; }]'. +!!! error TS2345: Type '{ y: boolean; }' is not assignable to type '{ x: any; y?: boolean; }'. +!!! error TS2345: Property 'x' is missing in type '{ y: boolean; }'. module M { export var [a, b] = [1, 2]; diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment2.errors.txt b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment2.errors.txt index 3348effe82..e22b23122d 100644 --- a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment2.errors.txt +++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment2.errors.txt @@ -2,8 +2,7 @@ tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAss tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment2.ts(3,12): error TS2525: Initializer provides no value for this binding element and the binding element has no default value. tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment2.ts(4,5): error TS2461: Type 'undefined' is not an array type. tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment2.ts(9,5): error TS2322: Type '[number, number, string]' is not assignable to type '[number, boolean, string]'. - Types of property '1' are incompatible. - Type 'number' is not assignable to type 'boolean'. + Type 'number' is not assignable to type 'boolean'. tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment2.ts(17,6): error TS2322: Type 'string' is not assignable to type 'Number'. tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment2.ts(22,5): error TS2322: Type 'number[]' is not assignable to type '[number, number]'. Property '0' is missing in type 'number[]'. @@ -30,8 +29,7 @@ tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAss var [b0, b1, b2]: [number, boolean, string] = [1, 2, "string"]; // Error ~~~~~~~~~~~~ !!! error TS2322: Type '[number, number, string]' is not assignable to type '[number, boolean, string]'. -!!! error TS2322: Types of property '1' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'boolean'. +!!! error TS2322: Type 'number' is not assignable to type 'boolean'. interface J extends Array { 2: number; } diff --git a/tests/baselines/reference/destructuringParameterDeclaration2.errors.txt b/tests/baselines/reference/destructuringParameterDeclaration2.errors.txt index 878bb38abf..d76a4efe5f 100644 --- a/tests/baselines/reference/destructuringParameterDeclaration2.errors.txt +++ b/tests/baselines/reference/destructuringParameterDeclaration2.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts(7,4): error TS2345: Argument of type '[number, string, string[][]]' is not assignable to parameter of type '[number, number, string[][]]'. - Types of property '1' are incompatible. - Type 'string' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts(7,29): error TS1005: ',' expected. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts(8,4): error TS2345: Argument of type '[number, number, string[][], string]' is not assignable to parameter of type '[number, number, string[][]]'. Types of property 'pop' are incompatible. @@ -32,12 +31,9 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts( Types of property '2' are incompatible. Type 'boolean' is not assignable to type '[[any]]'. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts(40,4): error TS2345: Argument of type '[number, number, [[string]]]' is not assignable to parameter of type '[any, any, [[number]]]'. - Types of property '2' are incompatible. - Type '[[string]]' is not assignable to type '[[number]]'. - Types of property '0' are incompatible. - Type '[string]' is not assignable to type '[number]'. - Types of property '0' are incompatible. - Type 'string' is not assignable to type 'number'. + Type '[[string]]' is not assignable to type '[[number]]'. + Type '[string]' is not assignable to type '[number]'. + Type 'string' is not assignable to type 'number'. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts(46,13): error TS2463: A binding pattern parameter cannot be optional in an implementation signature. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts(47,13): error TS2463: A binding pattern parameter cannot be optional in an implementation signature. tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts(55,7): error TS2420: Class 'C4' incorrectly implements interface 'F2'. @@ -62,8 +58,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts( a0([1, "string", [["world"]]); // Error ~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '[number, string, string[][]]' is not assignable to parameter of type '[number, number, string[][]]'. -!!! error TS2345: Types of property '1' are incompatible. -!!! error TS2345: Type 'string' is not assignable to type 'number'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. ~ !!! error TS1005: ',' expected. a0([1, 2, [["world"]], "string"]); // Error @@ -142,12 +137,9 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration2.ts( c6([1, 2, [["string"]]]); // Error, implied type is [any, any, [[number]]] // Use initializer ~~~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '[number, number, [[string]]]' is not assignable to parameter of type '[any, any, [[number]]]'. -!!! error TS2345: Types of property '2' are incompatible. -!!! error TS2345: Type '[[string]]' is not assignable to type '[[number]]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type '[string]' is not assignable to type '[number]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type 'string' is not assignable to type 'number'. +!!! error TS2345: Type '[[string]]' is not assignable to type '[[number]]'. +!!! error TS2345: Type '[string]' is not assignable to type '[number]'. +!!! error TS2345: Type 'string' is not assignable to type 'number'. // A parameter can be marked optional by following its name or binding pattern with a question mark (?) // or by including an initializer. Initializers (including binding property or element initializers) are diff --git a/tests/baselines/reference/destructuringParameterProperties2.errors.txt b/tests/baselines/reference/destructuringParameterProperties2.errors.txt index ec0f400631..deb039aa67 100644 --- a/tests/baselines/reference/destructuringParameterProperties2.errors.txt +++ b/tests/baselines/reference/destructuringParameterProperties2.errors.txt @@ -6,8 +6,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(9 tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(13,21): error TS2339: Property 'b' does not exist on type 'C1'. tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(17,21): error TS2339: Property 'c' does not exist on type 'C1'. tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(21,27): error TS2345: Argument of type '[number, undefined, string]' is not assignable to parameter of type '[number, string, boolean]'. - Types of property '2' are incompatible. - Type 'string' is not assignable to type 'boolean'. + Type 'string' is not assignable to type 'boolean'. ==== tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts (8 errors) ==== @@ -48,8 +47,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(2 var x = new C1(undefined, [0, undefined, ""]); ~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '[number, undefined, string]' is not assignable to parameter of type '[number, string, boolean]'. -!!! error TS2345: Types of property '2' are incompatible. -!!! error TS2345: Type 'string' is not assignable to type 'boolean'. +!!! error TS2345: Type 'string' is not assignable to type 'boolean'. var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()]; var y = new C1(10, [0, "", true]); diff --git a/tests/baselines/reference/destructuringParameterProperties5.errors.txt b/tests/baselines/reference/destructuringParameterProperties5.errors.txt index 6f5801b789..8eff6ad0fe 100644 --- a/tests/baselines/reference/destructuringParameterProperties5.errors.txt +++ b/tests/baselines/reference/destructuringParameterProperties5.errors.txt @@ -8,9 +8,8 @@ tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(7 tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(7,62): error TS2339: Property 'y' does not exist on type 'C1'. tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(7,72): error TS2339: Property 'z' does not exist on type 'C1'. tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(11,19): error TS2345: Argument of type '[{ x1: number; x2: string; x3: boolean; }, string, boolean]' is not assignable to parameter of type '[{ x: number; y: string; z: boolean; }, number, string]'. - Types of property '0' are incompatible. - Type '{ x1: number; x2: string; x3: boolean; }' is not assignable to type '{ x: number; y: string; z: boolean; }'. - Object literal may only specify known properties, and 'x1' does not exist in type '{ x: number; y: string; z: boolean; }'. + Type '{ x1: number; x2: string; x3: boolean; }' is not assignable to type '{ x: number; y: string; z: boolean; }'. + Object literal may only specify known properties, and 'x1' does not exist in type '{ x: number; y: string; z: boolean; }'. ==== tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts (10 errors) ==== @@ -45,7 +44,6 @@ tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(1 var a = new C1([{ x1: 10, x2: "", x3: true }, "", false]); ~~~~~~ !!! error TS2345: Argument of type '[{ x1: number; x2: string; x3: boolean; }, string, boolean]' is not assignable to parameter of type '[{ x: number; y: string; z: boolean; }, number, string]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type '{ x1: number; x2: string; x3: boolean; }' is not assignable to type '{ x: number; y: string; z: boolean; }'. -!!! error TS2345: Object literal may only specify known properties, and 'x1' does not exist in type '{ x: number; y: string; z: boolean; }'. +!!! error TS2345: Type '{ x1: number; x2: string; x3: boolean; }' is not assignable to type '{ x: number; y: string; z: boolean; }'. +!!! error TS2345: Object literal may only specify known properties, and 'x1' does not exist in type '{ x: number; y: string; z: boolean; }'. var [a_x1, a_x2, a_x3, a_y, a_z] = [a.x1, a.x2, a.x3, a.y, a.z]; \ No newline at end of file diff --git a/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt b/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt index 1a65583774..bdbda6f9a9 100644 --- a/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt +++ b/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt @@ -2,12 +2,9 @@ tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts(3 Types of property 'a1' are incompatible. Type 'boolean' is not assignable to type 'number'. tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts(4,5): error TS2322: Type '[number, [[boolean]], boolean]' is not assignable to type '[number, [[string]], boolean]'. - Types of property '1' are incompatible. - Type '[[boolean]]' is not assignable to type '[[string]]'. - Types of property '0' are incompatible. - Type '[boolean]' is not assignable to type '[string]'. - Types of property '0' are incompatible. - Type 'boolean' is not assignable to type 'string'. + Type '[[boolean]]' is not assignable to type '[[string]]'. + Type '[boolean]' is not assignable to type '[string]'. + Type 'boolean' is not assignable to type 'string'. tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts(9,25): error TS2322: Type '{ t1: boolean; t2: string; }' is not assignable to type '{ t1: boolean; t2: number; }'. Types of property 't2' are incompatible. Type 'string' is not assignable to type 'number'. @@ -28,12 +25,9 @@ tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts(1 var [a3, [[a4]], a5]: [number, [[string]], boolean] = [1, [[false]], true]; // Error ~~~~~~~~~~~~~~~~ !!! error TS2322: Type '[number, [[boolean]], boolean]' is not assignable to type '[number, [[string]], boolean]'. -!!! error TS2322: Types of property '1' are incompatible. -!!! error TS2322: Type '[[boolean]]' is not assignable to type '[[string]]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type '[boolean]' is not assignable to type '[string]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type 'boolean' is not assignable to type 'string'. +!!! error TS2322: Type '[[boolean]]' is not assignable to type '[[string]]'. +!!! error TS2322: Type '[boolean]' is not assignable to type '[string]'. +!!! error TS2322: Type 'boolean' is not assignable to type 'string'. // The type T associated with a destructuring variable declaration is determined as follows: // Otherwise, if the declaration includes an initializer expression, T is the type of that initializer expression. diff --git a/tests/baselines/reference/genericCallWithTupleType.errors.txt b/tests/baselines/reference/genericCallWithTupleType.errors.txt index 0194dc6131..617c4f7159 100644 --- a/tests/baselines/reference/genericCallWithTupleType.errors.txt +++ b/tests/baselines/reference/genericCallWithTupleType.errors.txt @@ -6,11 +6,9 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(14,1): error TS2322: Type '{ a: string; }' is not assignable to type 'string | number'. Type '{ a: string; }' is not assignable to type 'number'. tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(22,1): error TS2322: Type '[number, string]' is not assignable to type '[string, number]'. - Types of property '0' are incompatible. - Type 'number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(23,1): error TS2322: Type '[{}, {}]' is not assignable to type '[string, number]'. - Types of property '0' are incompatible. - Type '{}' is not assignable to type 'string'. + Type '{}' is not assignable to type 'string'. tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(24,1): error TS2322: Type '[{}]' is not assignable to type '[{}, {}]'. Property '1' is missing in type '[{}]'. @@ -49,13 +47,11 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup i1.tuple1 = [5, "foo"]; ~~~~~~~~~ !!! error TS2322: Type '[number, string]' is not assignable to type '[string, number]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. i1.tuple1 = [{}, {}]; ~~~~~~~~~ !!! error TS2322: Type '[{}, {}]' is not assignable to type '[string, number]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type '{}' is not assignable to type 'string'. +!!! error TS2322: Type '{}' is not assignable to type 'string'. i2.tuple1 = [{}]; ~~~~~~~~~ !!! error TS2322: Type '[{}]' is not assignable to type '[{}, {}]'. diff --git a/tests/baselines/reference/iterableArrayPattern29.errors.txt b/tests/baselines/reference/iterableArrayPattern29.errors.txt index b34d0317d5..29e5d0d2a3 100644 --- a/tests/baselines/reference/iterableArrayPattern29.errors.txt +++ b/tests/baselines/reference/iterableArrayPattern29.errors.txt @@ -1,7 +1,6 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern29.ts(1,33): error TS2501: A rest element cannot contain a binding pattern. tests/cases/conformance/es6/destructuring/iterableArrayPattern29.ts(2,21): error TS2345: Argument of type '[string, boolean]' is not assignable to parameter of type '[string, number]'. - Types of property '1' are incompatible. - Type 'boolean' is not assignable to type 'number'. + Type 'boolean' is not assignable to type 'number'. ==== tests/cases/conformance/es6/destructuring/iterableArrayPattern29.ts (2 errors) ==== @@ -11,5 +10,4 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern29.ts(2,21): error takeFirstTwoEntries(...new Map([["", true], ["hello", true]])); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '[string, boolean]' is not assignable to parameter of type '[string, number]'. -!!! error TS2345: Types of property '1' are incompatible. -!!! error TS2345: Type 'boolean' is not assignable to type 'number'. \ No newline at end of file +!!! error TS2345: Type 'boolean' is not assignable to type 'number'. \ No newline at end of file diff --git a/tests/baselines/reference/optionalBindingParameters1.errors.txt b/tests/baselines/reference/optionalBindingParameters1.errors.txt index 78fc1cbddf..0780c626ba 100644 --- a/tests/baselines/reference/optionalBindingParameters1.errors.txt +++ b/tests/baselines/reference/optionalBindingParameters1.errors.txt @@ -1,7 +1,6 @@ tests/cases/conformance/es6/destructuring/optionalBindingParameters1.ts(2,14): error TS2463: A binding pattern parameter cannot be optional in an implementation signature. tests/cases/conformance/es6/destructuring/optionalBindingParameters1.ts(8,5): error TS2345: Argument of type '[boolean, number, string]' is not assignable to parameter of type '[string, number, boolean]'. - Types of property '0' are incompatible. - Type 'boolean' is not assignable to type 'string'. + Type 'boolean' is not assignable to type 'string'. ==== tests/cases/conformance/es6/destructuring/optionalBindingParameters1.ts (2 errors) ==== @@ -17,5 +16,4 @@ tests/cases/conformance/es6/destructuring/optionalBindingParameters1.ts(8,5): er foo([false, 0, ""]); ~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '[boolean, number, string]' is not assignable to parameter of type '[string, number, boolean]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type 'boolean' is not assignable to type 'string'. \ No newline at end of file +!!! error TS2345: Type 'boolean' is not assignable to type 'string'. \ No newline at end of file diff --git a/tests/baselines/reference/optionalBindingParametersInOverloads1.errors.txt b/tests/baselines/reference/optionalBindingParametersInOverloads1.errors.txt index 312603d2c2..30ec4037c8 100644 --- a/tests/baselines/reference/optionalBindingParametersInOverloads1.errors.txt +++ b/tests/baselines/reference/optionalBindingParametersInOverloads1.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/es6/destructuring/optionalBindingParametersInOverloads1.ts(9,5): error TS2345: Argument of type '[boolean, number, string]' is not assignable to parameter of type '[string, number, boolean]'. - Types of property '0' are incompatible. - Type 'boolean' is not assignable to type 'string'. + Type 'boolean' is not assignable to type 'string'. ==== tests/cases/conformance/es6/destructuring/optionalBindingParametersInOverloads1.ts (1 errors) ==== @@ -15,5 +14,4 @@ tests/cases/conformance/es6/destructuring/optionalBindingParametersInOverloads1. foo([false, 0, ""]); ~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '[boolean, number, string]' is not assignable to parameter of type '[string, number, boolean]'. -!!! error TS2345: Types of property '0' are incompatible. -!!! error TS2345: Type 'boolean' is not assignable to type 'string'. \ No newline at end of file +!!! error TS2345: Type 'boolean' is not assignable to type 'string'. \ No newline at end of file diff --git a/tests/baselines/reference/tupleTypes.errors.txt b/tests/baselines/reference/tupleTypes.errors.txt index 75f413eb17..3b55476e4b 100644 --- a/tests/baselines/reference/tupleTypes.errors.txt +++ b/tests/baselines/reference/tupleTypes.errors.txt @@ -4,8 +4,7 @@ tests/cases/compiler/tupleTypes.ts(14,1): error TS2322: Type 'undefined[]' is no tests/cases/compiler/tupleTypes.ts(15,1): error TS2322: Type '[number]' is not assignable to type '[number, string]'. Property '1' is missing in type '[number]'. tests/cases/compiler/tupleTypes.ts(17,1): error TS2322: Type '[string, number]' is not assignable to type '[number, string]'. - Types of property '0' are incompatible. - Type 'string' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. tests/cases/compiler/tupleTypes.ts(41,1): error TS2322: Type 'undefined[]' is not assignable to type '[number, string]'. tests/cases/compiler/tupleTypes.ts(47,1): error TS2322: Type '[number, string]' is not assignable to type 'number[]'. Types of property 'pop' are incompatible. @@ -18,11 +17,9 @@ tests/cases/compiler/tupleTypes.ts(49,1): error TS2322: Type '[number, {}]' is n Type 'number | {}' is not assignable to type 'number'. Type '{}' is not assignable to type 'number'. tests/cases/compiler/tupleTypes.ts(50,1): error TS2322: Type '[number, number]' is not assignable to type '[number, string]'. - Types of property '1' are incompatible. - Type 'number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. tests/cases/compiler/tupleTypes.ts(51,1): error TS2322: Type '[number, {}]' is not assignable to type '[number, string]'. - Types of property '1' are incompatible. - Type '{}' is not assignable to type 'string'. + Type '{}' is not assignable to type 'string'. ==== tests/cases/compiler/tupleTypes.ts (9 errors) ==== @@ -53,8 +50,7 @@ tests/cases/compiler/tupleTypes.ts(51,1): error TS2322: Type '[number, {}]' is n t = ["hello", 1]; // Error ~ !!! error TS2322: Type '[string, number]' is not assignable to type '[number, string]'. -!!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type 'string' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. t = [1, "hello", 2]; // Ok var tf: [string, (x: string) => number] = ["hello", x => x.length]; @@ -104,13 +100,11 @@ tests/cases/compiler/tupleTypes.ts(51,1): error TS2322: Type '[number, {}]' is n a1 = a2; // Error ~~ !!! error TS2322: Type '[number, number]' is not assignable to type '[number, string]'. -!!! error TS2322: Types of property '1' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. a1 = a3; // Error ~~ !!! error TS2322: Type '[number, {}]' is not assignable to type '[number, string]'. -!!! error TS2322: Types of property '1' are incompatible. -!!! error TS2322: Type '{}' is not assignable to type 'string'. +!!! error TS2322: Type '{}' is not assignable to type 'string'. a3 = a1; a3 = a2; \ No newline at end of file From 05fef61e75a1d35c228b40e3096209118819dd66 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Mon, 22 Aug 2016 09:15:05 -0700 Subject: [PATCH 41/50] Add .types extension --- src/harness/rwcRunner.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index d56e8d6d35..ba1ab71ec1 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -158,13 +158,13 @@ namespace RWC { it("has the expected emitted code", () => { - Harness.Baseline.runBaseline(baseName + ".output.js", () => { + Harness.Baseline.runBaseline(`${baseName}.output.js`, () => { return Harness.Compiler.collateOutputs(compilerResult.files); }, baselineOpts); }); it("has the expected declaration file content", () => { - Harness.Baseline.runBaseline(baseName + ".d.ts", () => { + Harness.Baseline.runBaseline(`${baseName}.d.ts`, () => { if (!compilerResult.declFilesCode.length) { return null; } @@ -174,7 +174,7 @@ namespace RWC { }); it("has the expected source maps", () => { - Harness.Baseline.runBaseline(baseName + ".map", () => { + Harness.Baseline.runBaseline(`${baseName}.map`, () => { if (!compilerResult.sourceMaps.length) { return null; } @@ -192,7 +192,7 @@ namespace RWC { });*/ it("has the expected errors", () => { - Harness.Baseline.runBaseline(baseName + ".errors.txt", () => { + Harness.Baseline.runBaseline(`${baseName}.errors.txt`, () => { if (compilerResult.errors.length === 0) { return null; } @@ -207,7 +207,7 @@ namespace RWC { // declaration file errors as part of the baseline. it("has the expected errors in generated declaration files", () => { if (compilerOptions.declaration && !compilerResult.errors.length) { - Harness.Baseline.runBaseline(baseName + ".dts.errors.txt", () => { + Harness.Baseline.runBaseline(`${baseName}.dts.errors.txt`, () => { const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles( inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory); @@ -223,7 +223,7 @@ namespace RWC { }); it("has the expected types", () => { - Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles + Harness.Compiler.doTypeAndSymbolBaseline(`${baseName}.types`, compilerResult, inputFiles .concat(otherFiles) .filter(file => !!compilerResult.program.getSourceFile(file.unitName)) .filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts); From 4e56fc0d272e39706ea98bdff0ded79dc70ca1d6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 Aug 2016 09:49:26 -0700 Subject: [PATCH 42/50] Properly guard for undefined in getTypeReferenceArity --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9efaf72c03..3abf271a57 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4979,7 +4979,7 @@ namespace ts { } function getTypeReferenceArity(type: TypeReference): number { - return type.target.typeParameters.length; + return type.target.typeParameters ? type.target.typeParameters.length : 0; } // Get type from reference to class or interface From 2c814f4413cbc83a88c711823b0aea5125e8d343 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 22 Aug 2016 10:08:57 -0700 Subject: [PATCH 43/50] Add jsdoc nullable union test case to fourslash --- tests/cases/fourslash/jsdocNullableUnion.ts | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/cases/fourslash/jsdocNullableUnion.ts diff --git a/tests/cases/fourslash/jsdocNullableUnion.ts b/tests/cases/fourslash/jsdocNullableUnion.ts new file mode 100644 index 0000000000..19dc9818d6 --- /dev/null +++ b/tests/cases/fourslash/jsdocNullableUnion.ts @@ -0,0 +1,23 @@ +/// +// @allowNonTsExtensions: true +// @Filename: Foo.js +//// +//// * @param {never | {x: string}} p1 +//// * @param {undefined | {y: number}} p2 +//// * @param {null | {z: boolean}} p3 +//// * @returns {void} nothing +//// */ +////function f(p1, p2, p3) { +//// p1./*1*/ +//// p2./*2*/ +//// p3./*3*/ +////} + +goTo.marker('1'); +verify.memberListContains("x"); + +goTo.marker('2'); +verify.memberListContains("y"); + +goTo.marker('3'); +verify.memberListContains("z"); From 201305859f9a9a9fc7e93de59238e647c49ced51 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 Aug 2016 11:21:06 -0700 Subject: [PATCH 44/50] Fix class/interface merging issue + lint error --- src/compiler/checker.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3abf271a57..418f5e40a8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3564,11 +3564,13 @@ namespace ts { if (type.flags & TypeFlags.Tuple) { type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters))]; } - else if (type.symbol.flags & SymbolFlags.Class) { - resolveBaseTypesOfClass(type); - } - else if (type.symbol.flags & SymbolFlags.Interface) { - resolveBaseTypesOfInterface(type); + else if (type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + if (type.symbol.flags & SymbolFlags.Class) { + resolveBaseTypesOfClass(type); + } + if (type.symbol.flags & SymbolFlags.Interface) { + resolveBaseTypesOfInterface(type); + } } else { Debug.fail("type must be class or interface"); @@ -4972,7 +4974,7 @@ namespace ts { } function cloneTypeReference(source: TypeReference): TypeReference { - let type = createObjectType(source.flags, source.symbol); + const type = createObjectType(source.flags, source.symbol); type.target = source.target; type.typeArguments = source.typeArguments; return type; From 92eb8df68cd264cce733d6ad43ef2680f3f6ffcc Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 22 Aug 2016 13:03:49 -0700 Subject: [PATCH 45/50] Allow "typings" in a package.json to be missing its extension (but also allow it to have an extension) --- src/compiler/program.ts | 5 +- tests/baselines/reference/typingsLookup4.js | 36 +++++++ .../reference/typingsLookup4.symbols | 27 ++++++ .../reference/typingsLookup4.trace.json | 93 +++++++++++++++++++ .../baselines/reference/typingsLookup4.types | 30 ++++++ .../conformance/typings/typingsLookup4.ts | 31 +++++++ 6 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/typingsLookup4.js create mode 100644 tests/baselines/reference/typingsLookup4.symbols create mode 100644 tests/baselines/reference/typingsLookup4.trace.json create mode 100644 tests/baselines/reference/typingsLookup4.types create mode 100644 tests/cases/conformance/typings/typingsLookup4.ts diff --git a/src/compiler/program.ts b/src/compiler/program.ts index afd2ddad9e..f099d85811 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -720,8 +720,9 @@ namespace ts { const typesFile = tryReadTypesSection(packageJsonPath, candidate, state); if (typesFile) { const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host); - // The package.json "typings" property must specify the file with extension, so just try that exact filename. - const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state); + // A package.json "typings" may specify an exact filename, or may choose to omit an extension. + const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state) || + tryAddingExtensions(typesFile, extensions, failedLookupLocation, onlyRecordFailures, state); if (result) { return result; } diff --git a/tests/baselines/reference/typingsLookup4.js b/tests/baselines/reference/typingsLookup4.js new file mode 100644 index 0000000000..c11bc13c61 --- /dev/null +++ b/tests/baselines/reference/typingsLookup4.js @@ -0,0 +1,36 @@ +//// [tests/cases/conformance/typings/typingsLookup4.ts] //// + +//// [package.json] +{ "typings": "jquery.d.ts" } + +//// [jquery.d.ts] +export const j: number; + +//// [package.json] +{ "typings": "kquery" } + +//// [kquery.d.ts] +export const k: number; + +//// [package.json] +{ "typings": "lquery" } + +//// [lquery.ts] +export const l = 2; + +//// [a.ts] +import { j } from "jquery"; +import { k } from "kquery"; +import { l } from "lquery"; +j + k + l; + + +//// [lquery.js] +"use strict"; +exports.l = 2; +//// [a.js] +"use strict"; +var jquery_1 = require("jquery"); +var kquery_1 = require("kquery"); +var lquery_1 = require("lquery"); +jquery_1.j + kquery_1.k + lquery_1.l; diff --git a/tests/baselines/reference/typingsLookup4.symbols b/tests/baselines/reference/typingsLookup4.symbols new file mode 100644 index 0000000000..144548c645 --- /dev/null +++ b/tests/baselines/reference/typingsLookup4.symbols @@ -0,0 +1,27 @@ +=== /a.ts === +import { j } from "jquery"; +>j : Symbol(j, Decl(a.ts, 0, 8)) + +import { k } from "kquery"; +>k : Symbol(k, Decl(a.ts, 1, 8)) + +import { l } from "lquery"; +>l : Symbol(l, Decl(a.ts, 2, 8)) + +j + k + l; +>j : Symbol(j, Decl(a.ts, 0, 8)) +>k : Symbol(k, Decl(a.ts, 1, 8)) +>l : Symbol(l, Decl(a.ts, 2, 8)) + +=== /node_modules/@types/jquery/jquery.d.ts === +export const j: number; +>j : Symbol(j, Decl(jquery.d.ts, 0, 12)) + +=== /node_modules/@types/kquery/kquery.d.ts === +export const k: number; +>k : Symbol(k, Decl(kquery.d.ts, 0, 12)) + +=== /node_modules/@types/lquery/lquery.ts === +export const l = 2; +>l : Symbol(l, Decl(lquery.ts, 0, 12)) + diff --git a/tests/baselines/reference/typingsLookup4.trace.json b/tests/baselines/reference/typingsLookup4.trace.json new file mode 100644 index 0000000000..4bca8456f5 --- /dev/null +++ b/tests/baselines/reference/typingsLookup4.trace.json @@ -0,0 +1,93 @@ +[ + "======== Resolving module 'jquery' from '/a.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module 'jquery' from 'node_modules' folder.", + "File '/node_modules/jquery.ts' does not exist.", + "File '/node_modules/jquery.tsx' does not exist.", + "File '/node_modules/jquery.d.ts' does not exist.", + "File '/node_modules/jquery/package.json' does not exist.", + "File '/node_modules/jquery/index.ts' does not exist.", + "File '/node_modules/jquery/index.tsx' does not exist.", + "File '/node_modules/jquery/index.d.ts' does not exist.", + "File '/node_modules/@types/jquery.ts' does not exist.", + "File '/node_modules/@types/jquery.tsx' does not exist.", + "File '/node_modules/@types/jquery.d.ts' does not exist.", + "Found 'package.json' at '/node_modules/@types/jquery/package.json'.", + "'package.json' has 'typings' field 'jquery.d.ts' that references '/node_modules/@types/jquery/jquery.d.ts'.", + "File '/node_modules/@types/jquery/jquery.d.ts' exist - use it as a name resolution result.", + "Resolving real path for '/node_modules/@types/jquery/jquery.d.ts', result '/node_modules/@types/jquery/jquery.d.ts'", + "======== Module name 'jquery' was successfully resolved to '/node_modules/@types/jquery/jquery.d.ts'. ========", + "======== Resolving module 'kquery' from '/a.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module 'kquery' from 'node_modules' folder.", + "File '/node_modules/kquery.ts' does not exist.", + "File '/node_modules/kquery.tsx' does not exist.", + "File '/node_modules/kquery.d.ts' does not exist.", + "File '/node_modules/kquery/package.json' does not exist.", + "File '/node_modules/kquery/index.ts' does not exist.", + "File '/node_modules/kquery/index.tsx' does not exist.", + "File '/node_modules/kquery/index.d.ts' does not exist.", + "File '/node_modules/@types/kquery.ts' does not exist.", + "File '/node_modules/@types/kquery.tsx' does not exist.", + "File '/node_modules/@types/kquery.d.ts' does not exist.", + "Found 'package.json' at '/node_modules/@types/kquery/package.json'.", + "'package.json' has 'typings' field 'kquery' that references '/node_modules/@types/kquery/kquery'.", + "File '/node_modules/@types/kquery/kquery' does not exist.", + "File '/node_modules/@types/kquery/kquery.ts' does not exist.", + "File '/node_modules/@types/kquery/kquery.tsx' does not exist.", + "File '/node_modules/@types/kquery/kquery.d.ts' exist - use it as a name resolution result.", + "Resolving real path for '/node_modules/@types/kquery/kquery.d.ts', result '/node_modules/@types/kquery/kquery.d.ts'", + "======== Module name 'kquery' was successfully resolved to '/node_modules/@types/kquery/kquery.d.ts'. ========", + "======== Resolving module 'lquery' from '/a.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module 'lquery' from 'node_modules' folder.", + "File '/node_modules/lquery.ts' does not exist.", + "File '/node_modules/lquery.tsx' does not exist.", + "File '/node_modules/lquery.d.ts' does not exist.", + "File '/node_modules/lquery/package.json' does not exist.", + "File '/node_modules/lquery/index.ts' does not exist.", + "File '/node_modules/lquery/index.tsx' does not exist.", + "File '/node_modules/lquery/index.d.ts' does not exist.", + "File '/node_modules/@types/lquery.ts' does not exist.", + "File '/node_modules/@types/lquery.tsx' does not exist.", + "File '/node_modules/@types/lquery.d.ts' does not exist.", + "Found 'package.json' at '/node_modules/@types/lquery/package.json'.", + "'package.json' has 'typings' field 'lquery' that references '/node_modules/@types/lquery/lquery'.", + "File '/node_modules/@types/lquery/lquery' does not exist.", + "File '/node_modules/@types/lquery/lquery.ts' exist - use it as a name resolution result.", + "Resolving real path for '/node_modules/@types/lquery/lquery.ts', result '/node_modules/@types/lquery/lquery.ts'", + "======== Module name 'lquery' was successfully resolved to '/node_modules/@types/lquery/lquery.ts'. ========", + "======== Resolving type reference directive 'jquery', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'", + "Found 'package.json' at '/node_modules/@types/jquery/package.json'.", + "'package.json' has 'typings' field 'jquery.d.ts' that references '/node_modules/@types/jquery/jquery.d.ts'.", + "File '/node_modules/@types/jquery/jquery.d.ts' exist - use it as a name resolution result.", + "======== Type reference directive 'jquery' was successfully resolved to '/node_modules/@types/jquery/jquery.d.ts', primary: true. ========", + "======== Resolving type reference directive 'kquery', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'", + "Found 'package.json' at '/node_modules/@types/kquery/package.json'.", + "'package.json' has 'typings' field 'kquery' that references '/node_modules/@types/kquery/kquery'.", + "File '/node_modules/@types/kquery/kquery' does not exist.", + "File '/node_modules/@types/kquery/kquery.d.ts' exist - use it as a name resolution result.", + "======== Type reference directive 'kquery' was successfully resolved to '/node_modules/@types/kquery/kquery.d.ts', primary: true. ========", + "======== Resolving type reference directive 'lquery', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'", + "Found 'package.json' at '/node_modules/@types/lquery/package.json'.", + "'package.json' has 'typings' field 'lquery' that references '/node_modules/@types/lquery/lquery'.", + "File '/node_modules/@types/lquery/lquery' does not exist.", + "File '/node_modules/@types/lquery/lquery.d.ts' does not exist.", + "File '/node_modules/@types/lquery/index.d.ts' does not exist.", + "Looking up in 'node_modules' folder, initial location '/'", + "File '/node_modules/lquery.ts' does not exist.", + "File '/node_modules/lquery.d.ts' does not exist.", + "File '/node_modules/lquery/package.json' does not exist.", + "File '/node_modules/lquery/index.ts' does not exist.", + "File '/node_modules/lquery/index.d.ts' does not exist.", + "File '/node_modules/@types/lquery.ts' does not exist.", + "File '/node_modules/@types/lquery.d.ts' does not exist.", + "Found 'package.json' at '/node_modules/@types/lquery/package.json'.", + "'package.json' has 'typings' field 'lquery' that references '/node_modules/@types/lquery/lquery'.", + "File '/node_modules/@types/lquery/lquery' does not exist.", + "File '/node_modules/@types/lquery/lquery.ts' exist - use it as a name resolution result.", + "======== Type reference directive 'lquery' was successfully resolved to '/node_modules/@types/lquery/lquery.ts', primary: false. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/typingsLookup4.types b/tests/baselines/reference/typingsLookup4.types new file mode 100644 index 0000000000..d922c7b1df --- /dev/null +++ b/tests/baselines/reference/typingsLookup4.types @@ -0,0 +1,30 @@ +=== /a.ts === +import { j } from "jquery"; +>j : number + +import { k } from "kquery"; +>k : number + +import { l } from "lquery"; +>l : number + +j + k + l; +>j + k + l : number +>j + k : number +>j : number +>k : number +>l : number + +=== /node_modules/@types/jquery/jquery.d.ts === +export const j: number; +>j : number + +=== /node_modules/@types/kquery/kquery.d.ts === +export const k: number; +>k : number + +=== /node_modules/@types/lquery/lquery.ts === +export const l = 2; +>l : number +>2 : number + diff --git a/tests/cases/conformance/typings/typingsLookup4.ts b/tests/cases/conformance/typings/typingsLookup4.ts new file mode 100644 index 0000000000..234090aeba --- /dev/null +++ b/tests/cases/conformance/typings/typingsLookup4.ts @@ -0,0 +1,31 @@ +// @traceResolution: true +// @noImplicitReferences: true +// @currentDirectory: / +// A file extension is optional in typings entries. + +// @filename: /tsconfig.json +{} + +// @filename: /node_modules/@types/jquery/package.json +{ "typings": "jquery.d.ts" } + +// @filename: /node_modules/@types/jquery/jquery.d.ts +export const j: number; + +// @filename: /node_modules/@types/kquery/package.json +{ "typings": "kquery" } + +// @filename: /node_modules/@types/kquery/kquery.d.ts +export const k: number; + +// @filename: /node_modules/@types/lquery/package.json +{ "typings": "lquery" } + +// @filename: /node_modules/@types/lquery/lquery.ts +export const l = 2; + +// @filename: /a.ts +import { j } from "jquery"; +import { k } from "kquery"; +import { l } from "lquery"; +j + k + l; From 5aafc2c848ec209ec395428b76eb8a51341305d9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 22 Aug 2016 14:08:34 -0700 Subject: [PATCH 46/50] Contextually type this in getDeclFromSig, not checkThisExpr --- src/compiler/checker.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 17cfdf8976..81a9c639fe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3063,9 +3063,14 @@ namespace ts { } } // Use contextual parameter type if one is available - const type = declaration.symbol.name === "this" - ? getContextuallyTypedThisType(func) - : getContextuallyTypedParameterType(declaration); + let type: Type; + if (declaration.symbol.name === "this") { + const thisParameter = getContextuallyTypedThisParameter(func); + type = thisParameter ? getTypeOfSymbol(thisParameter) : undefined; + } + else { + type = getContextuallyTypedParameterType(declaration); + } if (type) { return addOptionality(type, /*optional*/ declaration.questionToken && includeOptionality); } @@ -4689,6 +4694,9 @@ namespace ts { if (isJSConstructSignature) { minArgumentCount--; } + if (!thisParameter && isObjectLiteralMethod(declaration)) { + thisParameter = getContextuallyTypedThisParameter(declaration); + } const classType = declaration.kind === SyntaxKind.Constructor ? getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent).symbol)) @@ -9087,10 +9095,6 @@ namespace ts { if (thisType) { return thisType; } - const type = getContextuallyTypedThisType(container); - if (type) { - return type; - } } if (isClassLike(container.parent)) { const symbol = getSymbolOfNode(container.parent); @@ -9326,11 +9330,11 @@ namespace ts { } } - function getContextuallyTypedThisType(func: FunctionLikeDeclaration): Type { + function getContextuallyTypedThisParameter(func: FunctionLikeDeclaration): Symbol { if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) { const contextualSignature = getContextualSignature(func); if (contextualSignature) { - return getThisTypeOfSignature(contextualSignature); + return contextualSignature.thisParameter; } } From 4a58e68d0040fb98e1be51ec9480d52a06bb8694 Mon Sep 17 00:00:00 2001 From: Yui Date: Mon, 22 Aug 2016 14:38:07 -0700 Subject: [PATCH 47/50] Update parser comment with es7 grammar (#10459) * Use ES7 term of ExponentiationExpression * Update timeout for mac OS * Address PR: add space --- Gulpfile.ts | 2 +- src/compiler/parser.ts | 42 +++++++++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/Gulpfile.ts b/Gulpfile.ts index 1b90256283..295a7ce03d 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -551,7 +551,7 @@ function restoreSavedNodeEnv() { process.env.NODE_ENV = savedNodeEnv; } -let testTimeout = 20000; +let testTimeout = 40000; function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: (e?: any) => void) { const lintFlag = cmdLineOptions["lint"]; cleanTestDirs((err) => { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d6a2cf88ed..f373d33955 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -912,7 +912,7 @@ namespace ts { // Note: it is not actually necessary to save/restore the context flags here. That's // because the saving/restoring of these flags happens naturally through the recursive // descent nature of our parser. However, we still store this here just so we can - // assert that that invariant holds. + // assert that invariant holds. const saveContextFlags = contextFlags; // If we're only looking ahead, then tell the scanner to only lookahead as well. @@ -2765,7 +2765,7 @@ namespace ts { // Note: for ease of implementation we treat productions '2' and '3' as the same thing. // (i.e. they're both BinaryExpressions with an assignment operator in it). - // First, do the simple check if we have a YieldExpression (production '5'). + // First, do the simple check if we have a YieldExpression (production '6'). if (isYieldExpression()) { return parseYieldExpression(); } @@ -3373,24 +3373,44 @@ namespace ts { } /** - * Parse ES7 unary expression and await expression + * Parse ES7 exponential expression and await expression + * + * ES7 ExponentiationExpression: + * 1) UnaryExpression[?Yield] + * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] * - * ES7 UnaryExpression: - * 1) SimpleUnaryExpression[?yield] - * 2) IncrementExpression[?yield] ** UnaryExpression[?yield] */ function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { if (isAwaitExpression()) { return parseAwaitExpression(); } - if (isIncrementExpression()) { + /** + * ES7 UpdateExpression: + * 1) LeftHandSideExpression[?Yield] + * 2) LeftHandSideExpression[?Yield][no LineTerminator here]++ + * 3) LeftHandSideExpression[?Yield][no LineTerminator here]-- + * 4) ++UnaryExpression[?Yield] + * 5) --UnaryExpression[?Yield] + */ + if (isUpdateExpression()) { const incrementExpression = parseIncrementExpression(); return token() === SyntaxKind.AsteriskAsteriskToken ? parseBinaryExpressionRest(getBinaryOperatorPrecedence(), incrementExpression) : incrementExpression; } + /** + * ES7 UnaryExpression: + * 1) UpdateExpression[?yield] + * 2) delete UpdateExpression[?yield] + * 3) void UpdateExpression[?yield] + * 4) typeof UpdateExpression[?yield] + * 5) + UpdateExpression[?yield] + * 6) - UpdateExpression[?yield] + * 7) ~ UpdateExpression[?yield] + * 8) ! UpdateExpression[?yield] + */ const unaryOperator = token(); const simpleUnaryExpression = parseSimpleUnaryExpression(); if (token() === SyntaxKind.AsteriskAsteriskToken) { @@ -3408,8 +3428,8 @@ namespace ts { /** * Parse ES7 simple-unary expression or higher: * - * ES7 SimpleUnaryExpression: - * 1) IncrementExpression[?yield] + * ES7 UnaryExpression: + * 1) UpdateExpression[?yield] * 2) delete UnaryExpression[?yield] * 3) void UnaryExpression[?yield] * 4) typeof UnaryExpression[?yield] @@ -3447,14 +3467,14 @@ namespace ts { /** * Check if the current token can possibly be an ES7 increment expression. * - * ES7 IncrementExpression: + * ES7 UpdateExpression: * LeftHandSideExpression[?Yield] * LeftHandSideExpression[?Yield][no LineTerminator here]++ * LeftHandSideExpression[?Yield][no LineTerminator here]-- * ++LeftHandSideExpression[?Yield] * --LeftHandSideExpression[?Yield] */ - function isIncrementExpression(): boolean { + function isUpdateExpression(): boolean { // This function is called inside parseUnaryExpression to decide // whether to call parseSimpleUnaryExpression or call parseIncrementExpression directly switch (token()) { From 046b55e9f152917e801f4279ded73d467c93ae8b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 22 Aug 2016 16:27:44 -0700 Subject: [PATCH 48/50] allowSyntheticDefaultImports resolves to modules instead of variables Fixes #10429 by improving the fix in #10096 --- src/compiler/checker.ts | 10 +++--- .../baselines/reference/tsxDefaultImports.js | 34 +++++++++++++++++++ .../reference/tsxDefaultImports.symbols | 29 ++++++++++++++++ .../reference/tsxDefaultImports.types | 29 ++++++++++++++++ tests/cases/compiler/tsxDefaultImports.ts | 12 +++++++ 5 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/tsxDefaultImports.js create mode 100644 tests/baselines/reference/tsxDefaultImports.symbols create mode 100644 tests/baselines/reference/tsxDefaultImports.types create mode 100644 tests/cases/compiler/tsxDefaultImports.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 193deded4c..aab284b0ce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1126,13 +1126,13 @@ namespace ts { else { symbolFromVariable = getPropertyOfVariable(targetSymbol, name.text); } - // If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default - if (!symbolFromVariable && allowSyntheticDefaultImports && name.text === "default") { - symbolFromVariable = resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol); - } // if symbolFromVariable is export - get its final target symbolFromVariable = resolveSymbol(symbolFromVariable); - const symbolFromModule = getExportOfModule(targetSymbol, name.text); + let symbolFromModule = getExportOfModule(targetSymbol, name.text); + // If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default + if (!symbolFromModule && allowSyntheticDefaultImports && name.text === "default") { + symbolFromModule = resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol); + } const symbol = symbolFromModule && symbolFromVariable ? combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) : symbolFromModule || symbolFromVariable; diff --git a/tests/baselines/reference/tsxDefaultImports.js b/tests/baselines/reference/tsxDefaultImports.js new file mode 100644 index 0000000000..79f5d2b8fa --- /dev/null +++ b/tests/baselines/reference/tsxDefaultImports.js @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/tsxDefaultImports.ts] //// + +//// [a.ts] + +enum SomeEnum { + one, +} +export default class SomeClass { + public static E = SomeEnum; +} + +//// [b.ts] +import {default as Def} from "./a" +let a = Def.E.one; + + +//// [a.js] +"use strict"; +var SomeEnum; +(function (SomeEnum) { + SomeEnum[SomeEnum["one"] = 0] = "one"; +})(SomeEnum || (SomeEnum = {})); +var SomeClass = (function () { + function SomeClass() { + } + SomeClass.E = SomeEnum; + return SomeClass; +}()); +exports.__esModule = true; +exports["default"] = SomeClass; +//// [b.js] +"use strict"; +var a_1 = require("./a"); +var a = a_1["default"].E.one; diff --git a/tests/baselines/reference/tsxDefaultImports.symbols b/tests/baselines/reference/tsxDefaultImports.symbols new file mode 100644 index 0000000000..e42392e24a --- /dev/null +++ b/tests/baselines/reference/tsxDefaultImports.symbols @@ -0,0 +1,29 @@ +=== tests/cases/compiler/a.ts === + +enum SomeEnum { +>SomeEnum : Symbol(SomeEnum, Decl(a.ts, 0, 0)) + + one, +>one : Symbol(SomeEnum.one, Decl(a.ts, 1, 15)) +} +export default class SomeClass { +>SomeClass : Symbol(SomeClass, Decl(a.ts, 3, 1)) + + public static E = SomeEnum; +>E : Symbol(SomeClass.E, Decl(a.ts, 4, 32)) +>SomeEnum : Symbol(SomeEnum, Decl(a.ts, 0, 0)) +} + +=== tests/cases/compiler/b.ts === +import {default as Def} from "./a" +>default : Symbol(Def, Decl(b.ts, 0, 8)) +>Def : Symbol(Def, Decl(b.ts, 0, 8)) + +let a = Def.E.one; +>a : Symbol(a, Decl(b.ts, 1, 3)) +>Def.E.one : Symbol(SomeEnum.one, Decl(a.ts, 1, 15)) +>Def.E : Symbol(Def.E, Decl(a.ts, 4, 32)) +>Def : Symbol(Def, Decl(b.ts, 0, 8)) +>E : Symbol(Def.E, Decl(a.ts, 4, 32)) +>one : Symbol(SomeEnum.one, Decl(a.ts, 1, 15)) + diff --git a/tests/baselines/reference/tsxDefaultImports.types b/tests/baselines/reference/tsxDefaultImports.types new file mode 100644 index 0000000000..a9bdedf3ef --- /dev/null +++ b/tests/baselines/reference/tsxDefaultImports.types @@ -0,0 +1,29 @@ +=== tests/cases/compiler/a.ts === + +enum SomeEnum { +>SomeEnum : SomeEnum + + one, +>one : SomeEnum +} +export default class SomeClass { +>SomeClass : SomeClass + + public static E = SomeEnum; +>E : typeof SomeEnum +>SomeEnum : typeof SomeEnum +} + +=== tests/cases/compiler/b.ts === +import {default as Def} from "./a" +>default : typeof Def +>Def : typeof Def + +let a = Def.E.one; +>a : SomeEnum +>Def.E.one : SomeEnum +>Def.E : typeof SomeEnum +>Def : typeof Def +>E : typeof SomeEnum +>one : SomeEnum + diff --git a/tests/cases/compiler/tsxDefaultImports.ts b/tests/cases/compiler/tsxDefaultImports.ts new file mode 100644 index 0000000000..4e313b33ea --- /dev/null +++ b/tests/cases/compiler/tsxDefaultImports.ts @@ -0,0 +1,12 @@ +// @Filename: a.ts + +enum SomeEnum { + one, +} +export default class SomeClass { + public static E = SomeEnum; +} + +// @Filename: b.ts +import {default as Def} from "./a" +let a = Def.E.one; From fc1d6a8437439b4caf232503baf07d1f5a4bf794 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 22 Aug 2016 16:36:38 -0700 Subject: [PATCH 49/50] Rename getContextuallyTypedThisParameter to getContextualThisParameter --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 81a9c639fe..2f2c300229 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3065,7 +3065,7 @@ namespace ts { // Use contextual parameter type if one is available let type: Type; if (declaration.symbol.name === "this") { - const thisParameter = getContextuallyTypedThisParameter(func); + const thisParameter = getContextualThisParameter(func); type = thisParameter ? getTypeOfSymbol(thisParameter) : undefined; } else { @@ -4695,7 +4695,7 @@ namespace ts { minArgumentCount--; } if (!thisParameter && isObjectLiteralMethod(declaration)) { - thisParameter = getContextuallyTypedThisParameter(declaration); + thisParameter = getContextualThisParameter(declaration); } const classType = declaration.kind === SyntaxKind.Constructor ? @@ -9330,7 +9330,7 @@ namespace ts { } } - function getContextuallyTypedThisParameter(func: FunctionLikeDeclaration): Symbol { + function getContextualThisParameter(func: FunctionLikeDeclaration): Symbol { if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) { const contextualSignature = getContextualSignature(func); if (contextualSignature) { From 36130ffa64ea95c6d924951ff2a2090504a0e94c Mon Sep 17 00:00:00 2001 From: Yui Date: Mon, 22 Aug 2016 16:37:04 -0700 Subject: [PATCH 50/50] Fix 10472: Invalid emitted code for await expression (#10483) * Properly emit await expression with yield expression * Add tests and update baselines * Move parsing await expression into parse unary-expression * Update incorrect comment --- src/compiler/emitter.ts | 4 ++ src/compiler/parser.ts | 11 ++-- .../reference/await_unaryExpression_es6.js | 47 ++++++++++++++++ .../await_unaryExpression_es6.symbols | 25 +++++++++ .../reference/await_unaryExpression_es6.types | 37 ++++++++++++ .../reference/await_unaryExpression_es6_1.js | 56 +++++++++++++++++++ .../await_unaryExpression_es6_1.symbols | 31 ++++++++++ .../await_unaryExpression_es6_1.types | 46 +++++++++++++++ .../reference/await_unaryExpression_es6_2.js | 38 +++++++++++++ .../await_unaryExpression_es6_2.symbols | 19 +++++++ .../await_unaryExpression_es6_2.types | 28 ++++++++++ .../await_unaryExpression_es6_3.errors.txt | 27 +++++++++ .../reference/await_unaryExpression_es6_3.js | 53 ++++++++++++++++++ tests/baselines/reference/castOfAwait.js | 6 +- .../async/es6/await_unaryExpression_es6.ts | 17 ++++++ .../async/es6/await_unaryExpression_es6_1.ts | 21 +++++++ .../async/es6/await_unaryExpression_es6_2.ts | 13 +++++ .../async/es6/await_unaryExpression_es6_3.ts | 19 +++++++ 18 files changed, 489 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/await_unaryExpression_es6.js create mode 100644 tests/baselines/reference/await_unaryExpression_es6.symbols create mode 100644 tests/baselines/reference/await_unaryExpression_es6.types create mode 100644 tests/baselines/reference/await_unaryExpression_es6_1.js create mode 100644 tests/baselines/reference/await_unaryExpression_es6_1.symbols create mode 100644 tests/baselines/reference/await_unaryExpression_es6_1.types create mode 100644 tests/baselines/reference/await_unaryExpression_es6_2.js create mode 100644 tests/baselines/reference/await_unaryExpression_es6_2.symbols create mode 100644 tests/baselines/reference/await_unaryExpression_es6_2.types create mode 100644 tests/baselines/reference/await_unaryExpression_es6_3.errors.txt create mode 100644 tests/baselines/reference/await_unaryExpression_es6_3.js create mode 100644 tests/cases/conformance/async/es6/await_unaryExpression_es6.ts create mode 100644 tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts create mode 100644 tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts create mode 100644 tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 357a15507a..d0f7918dc8 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1817,6 +1817,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge else if (node.parent.kind === SyntaxKind.ConditionalExpression && (node.parent).condition === node) { return true; } + else if (node.parent.kind === SyntaxKind.PrefixUnaryExpression || node.parent.kind === SyntaxKind.DeleteExpression || + node.parent.kind === SyntaxKind.TypeOfExpression || node.parent.kind === SyntaxKind.VoidExpression) { + return true; + } return false; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f373d33955..b5ba89887a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3381,10 +3381,6 @@ namespace ts { * */ function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { - if (isAwaitExpression()) { - return parseAwaitExpression(); - } - /** * ES7 UpdateExpression: * 1) LeftHandSideExpression[?Yield] @@ -3452,13 +3448,15 @@ namespace ts { return parseTypeOfExpression(); case SyntaxKind.VoidKeyword: return parseVoidExpression(); - case SyntaxKind.AwaitKeyword: - return parseAwaitExpression(); case SyntaxKind.LessThanToken: // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): // < type > UnaryExpression return parseTypeAssertion(); + case SyntaxKind.AwaitKeyword: + if (isAwaitExpression()) { + return parseAwaitExpression(); + } default: return parseIncrementExpression(); } @@ -3485,6 +3483,7 @@ namespace ts { case SyntaxKind.DeleteKeyword: case SyntaxKind.TypeOfKeyword: case SyntaxKind.VoidKeyword: + case SyntaxKind.AwaitKeyword: return false; case SyntaxKind.LessThanToken: // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression diff --git a/tests/baselines/reference/await_unaryExpression_es6.js b/tests/baselines/reference/await_unaryExpression_es6.js new file mode 100644 index 0000000000..46065bdada --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6.js @@ -0,0 +1,47 @@ +//// [await_unaryExpression_es6.ts] + +async function bar() { + !await 42; // OK +} + +async function bar1() { + +await 42; // OK +} + +async function bar3() { + -await 42; // OK +} + +async function bar4() { + ~await 42; // OK +} + +//// [await_unaryExpression_es6.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +function bar() { + return __awaiter(this, void 0, void 0, function* () { + !(yield 42); // OK + }); +} +function bar1() { + return __awaiter(this, void 0, void 0, function* () { + +(yield 42); // OK + }); +} +function bar3() { + return __awaiter(this, void 0, void 0, function* () { + -(yield 42); // OK + }); +} +function bar4() { + return __awaiter(this, void 0, void 0, function* () { + ~(yield 42); // OK + }); +} diff --git a/tests/baselines/reference/await_unaryExpression_es6.symbols b/tests/baselines/reference/await_unaryExpression_es6.symbols new file mode 100644 index 0000000000..81edd4b981 --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6.symbols @@ -0,0 +1,25 @@ +=== tests/cases/conformance/async/es6/await_unaryExpression_es6.ts === + +async function bar() { +>bar : Symbol(bar, Decl(await_unaryExpression_es6.ts, 0, 0)) + + !await 42; // OK +} + +async function bar1() { +>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6.ts, 3, 1)) + + +await 42; // OK +} + +async function bar3() { +>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6.ts, 7, 1)) + + -await 42; // OK +} + +async function bar4() { +>bar4 : Symbol(bar4, Decl(await_unaryExpression_es6.ts, 11, 1)) + + ~await 42; // OK +} diff --git a/tests/baselines/reference/await_unaryExpression_es6.types b/tests/baselines/reference/await_unaryExpression_es6.types new file mode 100644 index 0000000000..2a4b7354d3 --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/async/es6/await_unaryExpression_es6.ts === + +async function bar() { +>bar : () => Promise + + !await 42; // OK +>!await 42 : boolean +>await 42 : number +>42 : number +} + +async function bar1() { +>bar1 : () => Promise + + +await 42; // OK +>+await 42 : number +>await 42 : number +>42 : number +} + +async function bar3() { +>bar3 : () => Promise + + -await 42; // OK +>-await 42 : number +>await 42 : number +>42 : number +} + +async function bar4() { +>bar4 : () => Promise + + ~await 42; // OK +>~await 42 : number +>await 42 : number +>42 : number +} diff --git a/tests/baselines/reference/await_unaryExpression_es6_1.js b/tests/baselines/reference/await_unaryExpression_es6_1.js new file mode 100644 index 0000000000..c6f5f1142c --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_1.js @@ -0,0 +1,56 @@ +//// [await_unaryExpression_es6_1.ts] + +async function bar() { + !await 42; // OK +} + +async function bar1() { + delete await 42; // OK +} + +async function bar2() { + delete await 42; // OK +} + +async function bar3() { + void await 42; +} + +async function bar4() { + +await 42; +} + +//// [await_unaryExpression_es6_1.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +function bar() { + return __awaiter(this, void 0, void 0, function* () { + !(yield 42); // OK + }); +} +function bar1() { + return __awaiter(this, void 0, void 0, function* () { + delete (yield 42); // OK + }); +} +function bar2() { + return __awaiter(this, void 0, void 0, function* () { + delete (yield 42); // OK + }); +} +function bar3() { + return __awaiter(this, void 0, void 0, function* () { + void (yield 42); + }); +} +function bar4() { + return __awaiter(this, void 0, void 0, function* () { + +(yield 42); + }); +} diff --git a/tests/baselines/reference/await_unaryExpression_es6_1.symbols b/tests/baselines/reference/await_unaryExpression_es6_1.symbols new file mode 100644 index 0000000000..ed7d7e4ed0 --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_1.symbols @@ -0,0 +1,31 @@ +=== tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts === + +async function bar() { +>bar : Symbol(bar, Decl(await_unaryExpression_es6_1.ts, 0, 0)) + + !await 42; // OK +} + +async function bar1() { +>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6_1.ts, 3, 1)) + + delete await 42; // OK +} + +async function bar2() { +>bar2 : Symbol(bar2, Decl(await_unaryExpression_es6_1.ts, 7, 1)) + + delete await 42; // OK +} + +async function bar3() { +>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6_1.ts, 11, 1)) + + void await 42; +} + +async function bar4() { +>bar4 : Symbol(bar4, Decl(await_unaryExpression_es6_1.ts, 15, 1)) + + +await 42; +} diff --git a/tests/baselines/reference/await_unaryExpression_es6_1.types b/tests/baselines/reference/await_unaryExpression_es6_1.types new file mode 100644 index 0000000000..a5c3740b67 --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_1.types @@ -0,0 +1,46 @@ +=== tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts === + +async function bar() { +>bar : () => Promise + + !await 42; // OK +>!await 42 : boolean +>await 42 : number +>42 : number +} + +async function bar1() { +>bar1 : () => Promise + + delete await 42; // OK +>delete await 42 : boolean +>await 42 : number +>42 : number +} + +async function bar2() { +>bar2 : () => Promise + + delete await 42; // OK +>delete await 42 : boolean +>await 42 : number +>42 : number +} + +async function bar3() { +>bar3 : () => Promise + + void await 42; +>void await 42 : undefined +>await 42 : number +>42 : number +} + +async function bar4() { +>bar4 : () => Promise + + +await 42; +>+await 42 : number +>await 42 : number +>42 : number +} diff --git a/tests/baselines/reference/await_unaryExpression_es6_2.js b/tests/baselines/reference/await_unaryExpression_es6_2.js new file mode 100644 index 0000000000..3c341018ed --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_2.js @@ -0,0 +1,38 @@ +//// [await_unaryExpression_es6_2.ts] + +async function bar1() { + delete await 42; +} + +async function bar2() { + delete await 42; +} + +async function bar3() { + void await 42; +} + +//// [await_unaryExpression_es6_2.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +function bar1() { + return __awaiter(this, void 0, void 0, function* () { + delete (yield 42); + }); +} +function bar2() { + return __awaiter(this, void 0, void 0, function* () { + delete (yield 42); + }); +} +function bar3() { + return __awaiter(this, void 0, void 0, function* () { + void (yield 42); + }); +} diff --git a/tests/baselines/reference/await_unaryExpression_es6_2.symbols b/tests/baselines/reference/await_unaryExpression_es6_2.symbols new file mode 100644 index 0000000000..574ea4d433 --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_2.symbols @@ -0,0 +1,19 @@ +=== tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts === + +async function bar1() { +>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6_2.ts, 0, 0)) + + delete await 42; +} + +async function bar2() { +>bar2 : Symbol(bar2, Decl(await_unaryExpression_es6_2.ts, 3, 1)) + + delete await 42; +} + +async function bar3() { +>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6_2.ts, 7, 1)) + + void await 42; +} diff --git a/tests/baselines/reference/await_unaryExpression_es6_2.types b/tests/baselines/reference/await_unaryExpression_es6_2.types new file mode 100644 index 0000000000..b438f063ad --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_2.types @@ -0,0 +1,28 @@ +=== tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts === + +async function bar1() { +>bar1 : () => Promise + + delete await 42; +>delete await 42 : boolean +>await 42 : number +>42 : number +} + +async function bar2() { +>bar2 : () => Promise + + delete await 42; +>delete await 42 : boolean +>await 42 : number +>42 : number +} + +async function bar3() { +>bar3 : () => Promise + + void await 42; +>void await 42 : undefined +>await 42 : number +>42 : number +} diff --git a/tests/baselines/reference/await_unaryExpression_es6_3.errors.txt b/tests/baselines/reference/await_unaryExpression_es6_3.errors.txt new file mode 100644 index 0000000000..5518f84983 --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_3.errors.txt @@ -0,0 +1,27 @@ +tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts(3,7): error TS1109: Expression expected. +tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts(7,7): error TS1109: Expression expected. + + +==== tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts (2 errors) ==== + + async function bar1() { + ++await 42; // Error + ~~~~~ +!!! error TS1109: Expression expected. + } + + async function bar2() { + --await 42; // Error + ~~~~~ +!!! error TS1109: Expression expected. + } + + async function bar3() { + var x = 42; + await x++; // OK but shouldn't need parenthesis + } + + async function bar4() { + var x = 42; + await x--; // OK but shouldn't need parenthesis + } \ No newline at end of file diff --git a/tests/baselines/reference/await_unaryExpression_es6_3.js b/tests/baselines/reference/await_unaryExpression_es6_3.js new file mode 100644 index 0000000000..077e264c45 --- /dev/null +++ b/tests/baselines/reference/await_unaryExpression_es6_3.js @@ -0,0 +1,53 @@ +//// [await_unaryExpression_es6_3.ts] + +async function bar1() { + ++await 42; // Error +} + +async function bar2() { + --await 42; // Error +} + +async function bar3() { + var x = 42; + await x++; // OK but shouldn't need parenthesis +} + +async function bar4() { + var x = 42; + await x--; // OK but shouldn't need parenthesis +} + +//// [await_unaryExpression_es6_3.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +function bar1() { + return __awaiter(this, void 0, void 0, function* () { + ++; + yield 42; // Error + }); +} +function bar2() { + return __awaiter(this, void 0, void 0, function* () { + --; + yield 42; // Error + }); +} +function bar3() { + return __awaiter(this, void 0, void 0, function* () { + var x = 42; + yield x++; // OK but shouldn't need parenthesis + }); +} +function bar4() { + return __awaiter(this, void 0, void 0, function* () { + var x = 42; + yield x--; // OK but shouldn't need parenthesis + }); +} diff --git a/tests/baselines/reference/castOfAwait.js b/tests/baselines/reference/castOfAwait.js index 95817b7f0e..26e9812bf4 100644 --- a/tests/baselines/reference/castOfAwait.js +++ b/tests/baselines/reference/castOfAwait.js @@ -20,9 +20,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge function f() { return __awaiter(this, void 0, void 0, function* () { yield 0; - typeof yield 0; - void yield 0; - yield void typeof void yield 0; + typeof (yield 0); + void (yield 0); + yield void typeof void (yield 0); yield yield 0; }); } diff --git a/tests/cases/conformance/async/es6/await_unaryExpression_es6.ts b/tests/cases/conformance/async/es6/await_unaryExpression_es6.ts new file mode 100644 index 0000000000..09cf0a87a5 --- /dev/null +++ b/tests/cases/conformance/async/es6/await_unaryExpression_es6.ts @@ -0,0 +1,17 @@ +// @target: es6 + +async function bar() { + !await 42; // OK +} + +async function bar1() { + +await 42; // OK +} + +async function bar3() { + -await 42; // OK +} + +async function bar4() { + ~await 42; // OK +} \ No newline at end of file diff --git a/tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts b/tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts new file mode 100644 index 0000000000..5ccf1a1c35 --- /dev/null +++ b/tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts @@ -0,0 +1,21 @@ +// @target: es6 + +async function bar() { + !await 42; // OK +} + +async function bar1() { + delete await 42; // OK +} + +async function bar2() { + delete await 42; // OK +} + +async function bar3() { + void await 42; +} + +async function bar4() { + +await 42; +} \ No newline at end of file diff --git a/tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts b/tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts new file mode 100644 index 0000000000..24683765d1 --- /dev/null +++ b/tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts @@ -0,0 +1,13 @@ +// @target: es6 + +async function bar1() { + delete await 42; +} + +async function bar2() { + delete await 42; +} + +async function bar3() { + void await 42; +} \ No newline at end of file diff --git a/tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts b/tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts new file mode 100644 index 0000000000..b595ab5e74 --- /dev/null +++ b/tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts @@ -0,0 +1,19 @@ +// @target: es6 + +async function bar1() { + ++await 42; // Error +} + +async function bar2() { + --await 42; // Error +} + +async function bar3() { + var x = 42; + await x++; // OK but shouldn't need parenthesis +} + +async function bar4() { + var x = 42; + await x--; // OK but shouldn't need parenthesis +} \ No newline at end of file