From 40470ad6bcb1f051ed827446f05aeed7ae0e944a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Fri, 31 Aug 2018 16:45:25 +0800 Subject: [PATCH 1/9] fix lookup regression again and again --- src/compiler/checker.ts | 4 +++- ...arameterInitializersForwardReferencing1_es6.errors.txt | 5 ++++- .../parameterInitializersForwardReferencing1_es6.symbols | 2 +- .../parameterInitializersForwardReferencing1_es6.types | 8 ++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ebd849a7844..3ee631eb273 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1213,7 +1213,9 @@ namespace ts { } if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.Variable) { // expression inside parameter will lookup as normal variable scope when targeting es2015+ - if (compilerOptions.target && compilerOptions.target >= ScriptTarget.ES2015 && isParameter(lastLocation) && !isParameterPropertyDeclaration(lastLocation) && result.valueDeclaration.pos > lastLocation.end) { + const functionLocation = location; + if (compilerOptions.target && compilerOptions.target >= ScriptTarget.ES2015 && isParameter(lastLocation) && + functionLocation.body && result.valueDeclaration.pos >= functionLocation.body.pos && result.valueDeclaration.end <= functionLocation.body.end) { useResult = false; } else if (result.flags & SymbolFlags.FunctionScopedVariable) { diff --git a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt index 90390fbe3a4..59280d2006a 100644 --- a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt +++ b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt @@ -1,8 +1,9 @@ +tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(13,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(21,18): error TS2372: Parameter 'a' cannot be referenced in its initializer. tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(25,22): error TS2372: Parameter 'async' cannot be referenced in its initializer. -==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts (2 errors) ==== +==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts (3 errors) ==== let foo: string = ""; function f1 (bar = foo) { // unexpected compiler error; works at runtime @@ -16,6 +17,8 @@ tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.t } function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime + ~~~ +!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. return bar; } diff --git a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols index c0d42ab8b11..dcd204beb7b 100644 --- a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols +++ b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols @@ -31,7 +31,7 @@ function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime >f3 : Symbol(f3, Decl(parameterInitializersForwardReferencing1_es6.ts, 10, 1)) >bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 12, 13)) ->foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3)) +>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 12, 23)) >foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 12, 23)) return bar; diff --git a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types index 009ec47ddb8..8fc5d84ae8e 100644 --- a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types +++ b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types @@ -34,14 +34,14 @@ function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at } function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime ->f3 : (bar?: string, foo?: number) => string ->bar : string ->foo : string +>f3 : (bar?: number, foo?: number) => number +>bar : number +>foo : number >foo : number >2 : 2 return bar; ->bar : string +>bar : number } function f4 (foo, bar = foo) { From eb7fbdc4eba97954d9441e39b6e340d6a37a1e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Mon, 3 Sep 2018 16:37:34 +0800 Subject: [PATCH 2/9] update baseline --- ...ializersForwardReferencing1_es6.errors.txt | 8 ------ ...nitializersForwardReferencing1_es6.symbols | 6 ++--- ...rInitializersForwardReferencing1_es6.types | 26 +++++++++---------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt index 18823284b91..59280d2006a 100644 --- a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt +++ b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.errors.txt @@ -1,22 +1,17 @@ tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(13,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(21,18): error TS2372: Parameter 'a' cannot be referenced in its initializer. tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(25,22): error TS2372: Parameter 'async' cannot be referenced in its initializer. -tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(29,15): error TS2448: Block-scoped variable 'foo' used before its declaration. ==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts (3 errors) ==== let foo: string = ""; function f1 (bar = foo) { // unexpected compiler error; works at runtime - ~~~ -!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. var foo: number = 2; return bar; // returns 1 } function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime - ~~~ -!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. var foo: number = 2; return bar(); // returns 1 } @@ -44,9 +39,6 @@ tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.t } function f7({[foo]: bar}: any[]) { - ~~~ -!!! error TS2448: Block-scoped variable 'foo' used before its declaration. -!!! related TS2728 tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts:30:9: 'foo' is declared here. let foo: number = 2; } diff --git a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols index b44c91e8afd..dcd204beb7b 100644 --- a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols +++ b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.symbols @@ -5,7 +5,7 @@ let foo: string = ""; function f1 (bar = foo) { // unexpected compiler error; works at runtime >f1 : Symbol(f1, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 21)) >bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 2, 13)) ->foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 3, 7)) +>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3)) var foo: number = 2; >foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 3, 7)) @@ -18,7 +18,7 @@ function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at >f2 : Symbol(f2, Decl(parameterInitializersForwardReferencing1_es6.ts, 5, 1)) >bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 7, 13)) >baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1_es6.ts, 7, 20)) ->foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 8, 7)) +>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3)) >baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1_es6.ts, 7, 20)) var foo: number = 2; @@ -68,7 +68,7 @@ function f6 (async = async) { function f7({[foo]: bar}: any[]) { >f7 : Symbol(f7, Decl(parameterInitializersForwardReferencing1_es6.ts, 26, 1)) ->foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 29, 7)) +>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3)) >bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 28, 13)) let foo: number = 2; diff --git a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types index a58d19c5755..8fc5d84ae8e 100644 --- a/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types +++ b/tests/baselines/reference/parameterInitializersForwardReferencing1_es6.types @@ -4,33 +4,33 @@ let foo: string = ""; >"" : "" function f1 (bar = foo) { // unexpected compiler error; works at runtime ->f1 : (bar?: number) => number ->bar : number ->foo : number +>f1 : (bar?: string) => string +>bar : string +>foo : string var foo: number = 2; >foo : number >2 : 2 return bar; // returns 1 ->bar : number +>bar : string } function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime ->f2 : (bar?: (baz?: number) => number) => number ->bar : (baz?: number) => number ->(baz = foo) => baz : (baz?: number) => number ->baz : number ->foo : number ->baz : number +>f2 : (bar?: (baz?: string) => string) => string +>bar : (baz?: string) => string +>(baz = foo) => baz : (baz?: string) => string +>baz : string +>foo : string +>baz : string var foo: number = 2; >foo : number >2 : 2 return bar(); // returns 1 ->bar() : number ->bar : (baz?: number) => number +>bar() : string +>bar : (baz?: string) => string } function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime @@ -74,7 +74,7 @@ function f6 (async = async) { function f7({[foo]: bar}: any[]) { >f7 : ({ [foo]: bar }: any[]) => void ->foo : number +>foo : string >bar : any let foo: number = 2; From f30e73fc8028e482868c0ccbb7a9cf7b4a3983c6 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 5 Oct 2018 15:37:41 -0700 Subject: [PATCH 3/9] Report the errors for static incompatibility only if instance types are assignable Fixes #26138 --- src/compiler/checker.ts | 7 ++-- ...taticMismatchBecauseOfPrototype.errors.txt | 19 ++++++++++ .../staticMismatchBecauseOfPrototype.js | 36 +++++++++++++++++++ .../staticMismatchBecauseOfPrototype.symbols | 26 ++++++++++++++ .../staticMismatchBecauseOfPrototype.types | 22 ++++++++++++ .../staticMismatchBecauseOfPrototype.ts | 11 ++++++ 6 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/staticMismatchBecauseOfPrototype.errors.txt create mode 100644 tests/baselines/reference/staticMismatchBecauseOfPrototype.js create mode 100644 tests/baselines/reference/staticMismatchBecauseOfPrototype.symbols create mode 100644 tests/baselines/reference/staticMismatchBecauseOfPrototype.types create mode 100644 tests/cases/compiler/staticMismatchBecauseOfPrototype.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ba0b180b71f..2126b12894f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26069,8 +26069,11 @@ namespace ts { if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { issueMemberSpecificError(node, typeWithThis, baseWithThis, Diagnostics.Class_0_incorrectly_extends_base_class_1); } - checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, - Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); + else { + // Report static side error only when instance type is assignable + checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, + Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); + } if (baseConstructorType.flags & TypeFlags.TypeVariable && !isMixinConstructorType(staticType)) { error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any); } diff --git a/tests/baselines/reference/staticMismatchBecauseOfPrototype.errors.txt b/tests/baselines/reference/staticMismatchBecauseOfPrototype.errors.txt new file mode 100644 index 00000000000..49760196800 --- /dev/null +++ b/tests/baselines/reference/staticMismatchBecauseOfPrototype.errors.txt @@ -0,0 +1,19 @@ +tests/cases/compiler/staticMismatchBecauseOfPrototype.ts(10,5): error TS2416: Property 'n' in type 'B' is not assignable to the same property in base type 'A'. + Type 'string' is not assignable to type 'number'. + + +==== tests/cases/compiler/staticMismatchBecauseOfPrototype.ts (1 errors) ==== + interface A { + n: number; + } + declare var A: { + prototype: A; + new(): A; + }; + + class B extends A { + n = ""; + ~ +!!! error TS2416: Property 'n' in type 'B' is not assignable to the same property in base type 'A'. +!!! error TS2416: Type 'string' is not assignable to type 'number'. + } \ No newline at end of file diff --git a/tests/baselines/reference/staticMismatchBecauseOfPrototype.js b/tests/baselines/reference/staticMismatchBecauseOfPrototype.js new file mode 100644 index 00000000000..4bc7b248957 --- /dev/null +++ b/tests/baselines/reference/staticMismatchBecauseOfPrototype.js @@ -0,0 +1,36 @@ +//// [staticMismatchBecauseOfPrototype.ts] +interface A { + n: number; +} +declare var A: { + prototype: A; + new(): A; +}; + +class B extends A { + n = ""; +} + +//// [staticMismatchBecauseOfPrototype.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var B = /** @class */ (function (_super) { + __extends(B, _super); + function B() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.n = ""; + return _this; + } + return B; +}(A)); diff --git a/tests/baselines/reference/staticMismatchBecauseOfPrototype.symbols b/tests/baselines/reference/staticMismatchBecauseOfPrototype.symbols new file mode 100644 index 00000000000..98abd4b9e1c --- /dev/null +++ b/tests/baselines/reference/staticMismatchBecauseOfPrototype.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/staticMismatchBecauseOfPrototype.ts === +interface A { +>A : Symbol(A, Decl(staticMismatchBecauseOfPrototype.ts, 0, 0), Decl(staticMismatchBecauseOfPrototype.ts, 3, 11)) + + n: number; +>n : Symbol(A.n, Decl(staticMismatchBecauseOfPrototype.ts, 0, 13)) +} +declare var A: { +>A : Symbol(A, Decl(staticMismatchBecauseOfPrototype.ts, 0, 0), Decl(staticMismatchBecauseOfPrototype.ts, 3, 11)) + + prototype: A; +>prototype : Symbol(prototype, Decl(staticMismatchBecauseOfPrototype.ts, 3, 16)) +>A : Symbol(A, Decl(staticMismatchBecauseOfPrototype.ts, 0, 0), Decl(staticMismatchBecauseOfPrototype.ts, 3, 11)) + + new(): A; +>A : Symbol(A, Decl(staticMismatchBecauseOfPrototype.ts, 0, 0), Decl(staticMismatchBecauseOfPrototype.ts, 3, 11)) + +}; + +class B extends A { +>B : Symbol(B, Decl(staticMismatchBecauseOfPrototype.ts, 6, 2)) +>A : Symbol(A, Decl(staticMismatchBecauseOfPrototype.ts, 0, 0), Decl(staticMismatchBecauseOfPrototype.ts, 3, 11)) + + n = ""; +>n : Symbol(B.n, Decl(staticMismatchBecauseOfPrototype.ts, 8, 19)) +} diff --git a/tests/baselines/reference/staticMismatchBecauseOfPrototype.types b/tests/baselines/reference/staticMismatchBecauseOfPrototype.types new file mode 100644 index 00000000000..d55c86b3fc7 --- /dev/null +++ b/tests/baselines/reference/staticMismatchBecauseOfPrototype.types @@ -0,0 +1,22 @@ +=== tests/cases/compiler/staticMismatchBecauseOfPrototype.ts === +interface A { + n: number; +>n : number +} +declare var A: { +>A : { new (): A; prototype: A; } + + prototype: A; +>prototype : A + + new(): A; +}; + +class B extends A { +>B : B +>A : A + + n = ""; +>n : string +>"" : "" +} diff --git a/tests/cases/compiler/staticMismatchBecauseOfPrototype.ts b/tests/cases/compiler/staticMismatchBecauseOfPrototype.ts new file mode 100644 index 00000000000..24d50f1951d --- /dev/null +++ b/tests/cases/compiler/staticMismatchBecauseOfPrototype.ts @@ -0,0 +1,11 @@ +interface A { + n: number; +} +declare var A: { + prototype: A; + new(): A; +}; + +class B extends A { + n = ""; +} \ No newline at end of file From b4b29ab1e1365673c4db7c5cc96ece3f773ed39f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 9 Oct 2018 13:21:43 -0700 Subject: [PATCH 4/9] Converted legacySafelist to map to avoid using array prototype methods accidently to match with filename Eg. constructor.js was adding constructor function to aquisition.include which resulted in the mismatch between typing installer's typeAquisition (which was passed as JSON string and parsed back to null) and one in project That meant we kept on queuing the new typing installation request. Fixes #27435 --- src/server/editorServices.ts | 10 ++-- .../unittests/tsserverProjectSystem.ts | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 1fc71711eab..30a9844eaf8 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -486,7 +486,7 @@ namespace ts.server { private readonly hostConfiguration: HostConfiguration; private safelist: SafeList = defaultTypeSafeList; - private legacySafelist: { [key: string]: string } = {}; + private readonly legacySafelist = createMap(); private pendingProjectUpdates = createMap(); /* @internal */ @@ -638,14 +638,14 @@ namespace ts.server { this.safelist = raw.typesMap; for (const key in raw.simpleMap) { if (raw.simpleMap.hasOwnProperty(key)) { - this.legacySafelist[key] = raw.simpleMap[key].toLowerCase(); + this.legacySafelist.set(key, raw.simpleMap[key].toLowerCase()); } } } catch (e) { this.logger.info(`Error loading types map: ${e}`); this.safelist = defaultTypeSafeList; - this.legacySafelist = {}; + this.legacySafelist.clear(); } } @@ -2721,13 +2721,13 @@ namespace ts.server { if (fileExtensionIs(baseName, "js")) { const inferredTypingName = removeFileExtension(baseName); const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName); - if (this.legacySafelist[cleanedTypingName]) { + const typeName = this.legacySafelist.get(cleanedTypingName); + if (typeName !== undefined) { this.logger.info(`Excluded '${normalizedNames[i]}' because it matched ${cleanedTypingName} from the legacy safelist`); excludedFiles.push(normalizedNames[i]); // *exclude* it from the project... exclude = true; // ... but *include* it in the list of types to acquire - const typeName = this.legacySafelist[cleanedTypingName]; // Same best-effort dedupe as above if (typeAcqInclude.indexOf(typeName) < 0) { typeAcqInclude.push(typeName); diff --git a/src/testRunner/unittests/tsserverProjectSystem.ts b/src/testRunner/unittests/tsserverProjectSystem.ts index 2105ce6ef4b..9c4d776d54d 100644 --- a/src/testRunner/unittests/tsserverProjectSystem.ts +++ b/src/testRunner/unittests/tsserverProjectSystem.ts @@ -1826,6 +1826,63 @@ namespace ts.projectSystem { } }); + it("file with name constructor.js doesnt cause issue with typeAcquisition when safe type list", () => { + const file1 = { + path: "/a/b/f1.js", + content: `export let x = 5; import { s } from "s"` + }; + const constructorFile = { + path: "/a/b/constructor.js", + content: "const x = 10;" + }; + const bliss = { + path: "/a/b/bliss.js", + content: "export function is() { return true; }" + }; + const host = createServerHost([file1, libFile, constructorFile, bliss, customTypesMap]); + let request: string | undefined; + const cachePath = "/a/data"; + const typingsInstaller: server.ITypingsInstaller = { + isKnownTypesPackageName: returnFalse, + installPackage: notImplemented, + inspectValue: notImplemented, + enqueueInstallTypingsRequest: (proj, typeAcquisition, unresolvedImports) => { + assert.isUndefined(request); + request = JSON.stringify(server.createInstallTypingsRequest(proj, typeAcquisition, unresolvedImports || server.emptyArray, cachePath)); + }, + attach: noop, + onProjectClosed: noop, + globalTypingsCacheLocation: cachePath + }; + + const projectName = "project"; + const projectService = createProjectService(host, { typingsInstaller }); + projectService.openExternalProject({ projectFileName: projectName, options: {}, rootFiles: toExternalFiles([file1.path, constructorFile.path, bliss.path]) }); + assert.equal(request, JSON.stringify({ + projectName, + fileNames: [libFile.path, file1.path, constructorFile.path, bliss.path], + compilerOptions: { allowNonTsExtensions: true, noEmitForJsFiles: true }, + typeAcquisition: { include: ["blissfuljs"], exclude: [], enable: true }, + unresolvedImports: ["s"], + projectRootPath: "/", + cachePath, + kind: "discover" + })); + const response = JSON.parse(request!); + request = undefined; + projectService.updateTypingsForProject({ + kind: "action::set", + projectName: response.projectName, + typeAcquisition: response.typeAcquisition, + compilerOptions: response.compilerOptions, + typings: emptyArray, + unresolvedImports: response.unresolvedImports, + }); + + host.checkTimeoutQueueLengthAndRun(2); + assert.isUndefined(request); + }); + it("ignores files excluded by the default type list", () => { const file1 = { path: "/a/b/f1.js", From 23ec0c44846036005035317f5e5f27421d443cb6 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 9 Oct 2018 13:45:17 -0700 Subject: [PATCH 5/9] Accept public api change --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 0120e49f0a5..d8306559986 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -8497,7 +8497,7 @@ declare namespace ts.server { private readonly throttledOperations; private readonly hostConfiguration; private safelist; - private legacySafelist; + private readonly legacySafelist; private pendingProjectUpdates; readonly currentDirectory: NormalizedPath; readonly toCanonicalFileName: (f: string) => string; From ba0f5581f6fd571f7c6b06a9f459e5c477be628e Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 10 Oct 2018 12:51:58 -0700 Subject: [PATCH 6/9] Remove any existing errors in case of successful build in tsbuild watch mode Fixes #27685 --- src/compiler/tsbuild.ts | 3 ++ src/testRunner/unittests/tsbuildWatchMode.ts | 52 ++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index 5d27e6a79f6..c2215b22ebf 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -1066,6 +1066,9 @@ namespace ts { type: UpToDateStatusType.UpToDate, newestDeclarationFileContentChangedTime: anyDtsChanged ? maximumDate : newestDeclarationFileContentChangedTime }; + if (options.watch) { + diagnostics.removeKey(proj); + } projectStatus.setValue(proj, status); return resultFlags; diff --git a/src/testRunner/unittests/tsbuildWatchMode.ts b/src/testRunner/unittests/tsbuildWatchMode.ts index 2ffe51189d8..884042a9c8f 100644 --- a/src/testRunner/unittests/tsbuildWatchMode.ts +++ b/src/testRunner/unittests/tsbuildWatchMode.ts @@ -356,6 +356,58 @@ function myFunc() { return 100; }`); } }); + it("when referenced project change introduces error in the down stream project and then fixes it", () => { + const subProjectLibrary = `${projectsLocation}/${project}/Library`; + const libraryTs: File = { + path: `${subProjectLibrary}/library.ts`, + content: ` +interface SomeObject +{ + message: string; +} + +export function createSomeObject(): SomeObject +{ + return { + message: "new Object" + }; +}` + }; + const libraryTsconfig: File = { + path: `${subProjectLibrary}/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { composite: true } }) + }; + const subProjectApp = `${projectsLocation}/${project}/App`; + const appTs: File = { + path: `${subProjectApp}/app.ts`, + content: `import { createSomeObject } from "../Library/library"; +createSomeObject().message;` + }; + const appTsconfig: File = { + path: `${subProjectApp}/tsconfig.json`, + content: JSON.stringify({ references: [{ path: "../Library" }] }) + }; + + const files = [libFile, libraryTs, libraryTsconfig, appTs, appTsconfig]; + const host = createWatchedSystem(files, { currentDirectory: `${projectsLocation}/${project}` }); + createSolutionBuilderWithWatch(host, ["App"]); + checkOutputErrorsInitial(host, emptyArray); + + // Change message in library to message2 + host.writeFile(libraryTs.path, libraryTs.content.replace(/message/g, "message2")); + host.checkTimeoutQueueLengthAndRun(1); // Build library + host.checkTimeoutQueueLengthAndRun(1); // Build App + checkOutputErrorsIncremental(host, [ + "App/app.ts(2,20): error TS2551: Property 'message' does not exist on type 'SomeObject'. Did you mean 'message2'?\n" + ]); + + // Revert library changes + host.writeFile(libraryTs.path, libraryTs.content); + host.checkTimeoutQueueLengthAndRun(1); // Build library + host.checkTimeoutQueueLengthAndRun(1); // Build App + checkOutputErrorsIncremental(host, emptyArray); + }); + describe("reports errors in all projects on incremental compile", () => { function verifyIncrementalErrors(defaultBuildOptions?: BuildOptions, disabledConsoleClear?: boolean) { const host = createSolutionInWatchMode(allFiles, defaultBuildOptions, disabledConsoleClear); From dd764b318f965c7104aa6a02318614069beaf1fc Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 10 Oct 2018 13:45:52 -0700 Subject: [PATCH 7/9] importFixes: Skip alias when testing isTypeOnlySymbol (#27674) --- src/services/codefixes/importFixes.ts | 12 ++++++------ .../importNameCodeFix_defaultExport.ts | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/importNameCodeFix_defaultExport.ts diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 578f55f5c68..2f6d68c52f4 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -185,20 +185,20 @@ namespace ts.codefix { const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); if (defaultInfo && defaultInfo.name === symbolName && skipAlias(defaultInfo.symbol, checker) === exportedSymbol) { - result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol) }); + result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol, checker) }); } for (const exported of checker.getExportsOfModule(moduleSymbol)) { if (exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) { - result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) }); + result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported, checker) }); } } }); return result; } - function isTypeOnlySymbol(s: Symbol): boolean { - return !(s.flags & SymbolFlags.Value); + function isTypeOnlySymbol(s: Symbol, checker: TypeChecker): boolean { + return !(skipAlias(s, checker).flags & SymbolFlags.Value); } function getFixForImport( @@ -398,7 +398,7 @@ namespace ts.codefix { // Maps symbol id to info for modules providing that symbol (original export + re-exports). const originalSymbolToExportInfos = createMultiMap(); function addSymbol(moduleSymbol: Symbol, exportedSymbol: Symbol, importKind: ImportKind): void { - originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { moduleSymbol, importKind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exportedSymbol) }); + originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { moduleSymbol, importKind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exportedSymbol, checker) }); } forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => { cancellationToken.throwIfCancellationRequested(); @@ -424,7 +424,7 @@ namespace ts.codefix { if (!exported) return undefined; const { symbol, kind } = exported; const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions); - return info && { symbol, symbolForMeaning: info.symbolForMeaning, name: info.name, kind }; + return info && { symbol, kind, ...info }; } function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined { diff --git a/tests/cases/fourslash/importNameCodeFix_defaultExport.ts b/tests/cases/fourslash/importNameCodeFix_defaultExport.ts new file mode 100644 index 00000000000..fa8cef71c99 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFix_defaultExport.ts @@ -0,0 +1,18 @@ +/// + +// @allowJs: true +// @checkJs: true + +// @Filename: /a.js +////class C {} +////export default C; + +// @Filename: /b.js +////[|C;|] + +goTo.file("/b.js"); +verify.importFixAtPosition([ +`import C from "./a"; + +C;`, +]); From d493c47aac96b76e25987e42c7e91bccd46481f9 Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Thu, 11 Oct 2018 09:58:25 -0700 Subject: [PATCH 8/9] Update user baselines (#27710) --- tests/baselines/reference/user/enhanced-resolve.log | 6 +++--- tests/baselines/reference/user/npm.log | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/user/enhanced-resolve.log b/tests/baselines/reference/user/enhanced-resolve.log index 24d0c3b9839..7dd284bf166 100644 --- a/tests/baselines/reference/user/enhanced-resolve.log +++ b/tests/baselines/reference/user/enhanced-resolve.log @@ -1,10 +1,10 @@ Exit Code: 1 Standard output: -node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(116,18): error TS2345: Argument of type 'Timer | null' is not assignable to parameter of type 'number | undefined'. +node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(116,18): error TS2345: Argument of type 'Timeout | null' is not assignable to parameter of type 'number | undefined'. Type 'null' is not assignable to type 'number | undefined'. -node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(129,18): error TS2345: Argument of type 'Timer | null' is not assignable to parameter of type 'number | undefined'. +node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(129,18): error TS2345: Argument of type 'Timeout | null' is not assignable to parameter of type 'number | undefined'. Type 'null' is not assignable to type 'number | undefined'. -node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(147,18): error TS2345: Argument of type 'Timer | null' is not assignable to parameter of type 'number | undefined'. +node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(147,18): error TS2345: Argument of type 'Timeout | null' is not assignable to parameter of type 'number | undefined'. Type 'null' is not assignable to type 'number | undefined'. node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(176,19): error TS2322: Type 'null' is not assignable to type '(path: any, callback: any) => void'. node_modules/enhanced-resolve/lib/CachedInputFileSystem.js(179,23): error TS2322: Type 'null' is not assignable to type '(path: any) => any'. diff --git a/tests/baselines/reference/user/npm.log b/tests/baselines/reference/user/npm.log index 1caa051e2de..435d962fa95 100644 --- a/tests/baselines/reference/user/npm.log +++ b/tests/baselines/reference/user/npm.log @@ -919,6 +919,8 @@ node_modules/npm/test/broken-under-nyc-and-travis/whoami.js(7,20): error TS2307: node_modules/npm/test/common-tap.js(5,47): error TS2339: Property '_extend' does not exist on type 'typeof import("util")'. node_modules/npm/test/common-tap.js(10,3): error TS2322: Type '(...args: any[]) => void' is not assignable to type 'typeof setImmediate'. Property '__promisify__' is missing in type '(...args: any[]) => void'. +node_modules/npm/test/common-tap.js(10,36): error TS2322: Type '(...args: any[]) => void' is not assignable to type '(callback: (...args: any[]) => void, ...args: any[]) => Immediate'. + Type 'void' is not assignable to type 'Immediate'. node_modules/npm/test/common-tap.js(12,28): error TS2345: Argument of type 'any[]' is not assignable to parameter of type '[(...args: any[]) => void, number, ...any[]]'. Property '0' is missing in type 'any[]'. node_modules/npm/test/common-tap.js(175,17): error TS2339: Property '_storage' does not exist on type 'Environment'. From 0d91838593e8108e2183ff7dacfdc16c04a8b06b Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 11 Oct 2018 10:09:47 -0700 Subject: [PATCH 9/9] Do not generate jsFile path if its emitOnlyDeclarations is set Fixes #27009 --- src/compiler/emitter.ts | 45 ++++++++++++++--------- src/compiler/transformers/declarations.ts | 2 +- src/compiler/utilities.ts | 2 +- src/testRunner/unittests/tsbuild.ts | 2 + 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index fe54402d434..6b4b3a5c510 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -41,20 +41,23 @@ namespace ts { export function getOutputPathsFor(sourceFile: SourceFile | Bundle, host: EmitHost, forceDtsPaths: boolean): EmitFileNames { const options = host.getCompilerOptions(); if (sourceFile.kind === SyntaxKind.Bundle) { - const jsFilePath = options.outFile || options.out!; - const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options); - const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(jsFilePath) + Extension.Dts : undefined; - const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; + const outPath = options.outFile || options.out!; + const jsFilePath = options.emitDeclarationOnly ? undefined : outPath; + const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options); + const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined; + const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; const bundleInfoPath = options.references && jsFilePath ? (removeFileExtension(jsFilePath) + infoExtension) : undefined; return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath }; } else { - const jsFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile, options)); - const sourceMapFilePath = isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options); + const ownOutputFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile, options)); + // If json file emits to the same location skip writing it, if emitDeclarationOnly skip writing it + const jsFilePath = options.emitDeclarationOnly ? undefined : ownOutputFilePath; + const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options); // For legacy reasons (ie, we have baselines capturing the behavior), js files don't report a .d.ts output path - this would only matter if `declaration` and `allowJs` were both on, which is currently an error const isJs = isSourceFileJS(sourceFile); const declarationFilePath = ((forceDtsPaths || getEmitDeclarations(options)) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined; - const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; + const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath: undefined }; } } @@ -135,27 +138,33 @@ namespace ts { if (!emitSkipped && emittedFilesList) { if (!emitOnlyDtsFiles) { - emittedFilesList.push(jsFilePath); - } - if (sourceMapFilePath) { - emittedFilesList.push(sourceMapFilePath); + if (jsFilePath) { + emittedFilesList.push(jsFilePath); + } + if (sourceMapFilePath) { + emittedFilesList.push(sourceMapFilePath); + } + if (bundleInfoPath) { + emittedFilesList.push(bundleInfoPath); + } } if (declarationFilePath) { emittedFilesList.push(declarationFilePath); } - if (bundleInfoPath) { - emittedFilesList.push(bundleInfoPath); + if (declarationMapPath) { + emittedFilesList.push(declarationMapPath); } } } - function emitJsFileOrBundle(sourceFileOrBundle: SourceFile | Bundle, jsFilePath: string, sourceMapFilePath: string | undefined, bundleInfoPath: string | undefined) { - // Make sure not to write js file and source map file if any of them cannot be written - if (host.isEmitBlocked(jsFilePath) || compilerOptions.noEmit || compilerOptions.emitDeclarationOnly) { - emitSkipped = true; + function emitJsFileOrBundle(sourceFileOrBundle: SourceFile | Bundle, jsFilePath: string | undefined, sourceMapFilePath: string | undefined, bundleInfoPath: string | undefined) { + if (emitOnlyDtsFiles || !jsFilePath) { return; } - if (emitOnlyDtsFiles) { + + // Make sure not to write js file and source map file if any of them cannot be written + if ((jsFilePath && host.isEmitBlocked(jsFilePath)) || compilerOptions.noEmit) { + emitSkipped = true; return; } // Transform the source files diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 5312efb5aac..00e787c421b 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -275,7 +275,7 @@ namespace ts { else { if (isBundledEmit && contains((node as Bundle).sourceFiles, file)) return; // Omit references to files which are being merged const paths = getOutputPathsFor(file, host, /*forceDtsPaths*/ true); - declFileName = paths.declarationFilePath || paths.jsFilePath; + declFileName = paths.declarationFilePath || paths.jsFilePath || file.fileName; } if (declFileName) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index ae75290d56e..564e74fc4d3 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3245,7 +3245,7 @@ namespace ts { } export interface EmitFileNames { - jsFilePath: string; + jsFilePath: string | undefined; sourceMapFilePath: string | undefined; declarationFilePath: string | undefined; declarationMapPath: string | undefined; diff --git a/src/testRunner/unittests/tsbuild.ts b/src/testRunner/unittests/tsbuild.ts index 36feb68a223..94af1241ab0 100644 --- a/src/testRunner/unittests/tsbuild.ts +++ b/src/testRunner/unittests/tsbuild.ts @@ -347,8 +347,10 @@ export class cNew {}`); assert.deepEqual(host.traces, [ "TSFILE: /src/core/anotherModule.js", "TSFILE: /src/core/anotherModule.d.ts", + "TSFILE: /src/core/anotherModule.d.ts.map", "TSFILE: /src/core/index.js", "TSFILE: /src/core/index.d.ts", + "TSFILE: /src/core/index.d.ts.map", "TSFILE: /src/logic/index.js", "TSFILE: /src/logic/index.js.map", "TSFILE: /src/logic/index.d.ts",