From e0599fd19cc690aca5fb74e18dbee5eed1b446a0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 12 Jul 2019 11:11:36 -1000 Subject: [PATCH 01/30] Instantiate contextual type for return type in getReturnTypeFromBody --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b761606fcb3..1f8c62d0858 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19051,7 +19051,7 @@ namespace ts { // If the given contextual type contains instantiable types and if a mapper representing // return type inferences is available, instantiate those types using that mapper. - function instantiateContextualType(contextualType: Type | undefined, node: Expression, contextFlags?: ContextFlags): Type | undefined { + function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags?: ContextFlags): Type | undefined { if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) { const inferenceContext = getInferenceContext(node); // If no inferences have been made, nothing is gained from instantiating as type parameters @@ -23363,7 +23363,7 @@ namespace ts { nextType && isUnitType(nextType)) { const contextualType = !contextualSignature ? undefined : contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType : - getReturnTypeOfSignature(contextualSignature); + instantiateContextualType(getReturnTypeOfSignature(contextualSignature), func); if (isGenerator) { yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(yieldType, contextualType, IterationTypeKind.Yield, isAsync); returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(returnType, contextualType, IterationTypeKind.Return, isAsync); From 044d70fc243e7f68214796611d8b93c0e31dec65 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 12 Jul 2019 17:57:05 -1000 Subject: [PATCH 02/30] Add regression tests --- .../compiler/instantiateContextualTypes.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/cases/compiler/instantiateContextualTypes.ts b/tests/cases/compiler/instantiateContextualTypes.ts index b81356fa91e..3165011ecff 100644 --- a/tests/cases/compiler/instantiateContextualTypes.ts +++ b/tests/cases/compiler/instantiateContextualTypes.ts @@ -140,3 +140,37 @@ declare function passContentsToFunc(outerBox: T, consumer: BoxConsumerFromOut declare const outerBoxOfString: OuterBox; passContentsToFunc(outerBoxOfString, box => box.value); + +// Repro from #32349 + +type DooDad = 'SOMETHING' | 'ELSE' ; + +class Interesting { + public compiles = () : Promise => { + return Promise.resolve().then(() => { + if (1 < 2) { + return 'SOMETHING'; + } + return 'ELSE'; + }); + }; + public doesnt = () : Promise => { + return Promise.resolve().then(() => { + return 'ELSE'; + }); + }; + public slightlyDifferentErrorMessage = () : Promise => { + return Promise.resolve().then(() => { + if (1 < 2) { + return 'SOMETHING'; + } + return 'SOMETHING'; + }); + }; +} + +// Repro from #32349 + +declare function invoke(f: () => T): T; + +let xx: 0 | 1 | 2 = invoke(() => 1); From 6f637b0870f27fcae5cfdc5ee97e212017e1ecde Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 12 Jul 2019 17:57:11 -1000 Subject: [PATCH 03/30] Accept new baselines --- .../reference/instantiateContextualTypes.js | 60 ++++++++++++ .../instantiateContextualTypes.symbols | 74 ++++++++++++++ .../instantiateContextualTypes.types | 96 +++++++++++++++++++ 3 files changed, 230 insertions(+) diff --git a/tests/baselines/reference/instantiateContextualTypes.js b/tests/baselines/reference/instantiateContextualTypes.js index 3a33b54278c..9de6bfb612c 100644 --- a/tests/baselines/reference/instantiateContextualTypes.js +++ b/tests/baselines/reference/instantiateContextualTypes.js @@ -138,6 +138,40 @@ declare function passContentsToFunc(outerBox: T, consumer: BoxConsumerFromOut declare const outerBoxOfString: OuterBox; passContentsToFunc(outerBoxOfString, box => box.value); + +// Repro from #32349 + +type DooDad = 'SOMETHING' | 'ELSE' ; + +class Interesting { + public compiles = () : Promise => { + return Promise.resolve().then(() => { + if (1 < 2) { + return 'SOMETHING'; + } + return 'ELSE'; + }); + }; + public doesnt = () : Promise => { + return Promise.resolve().then(() => { + return 'ELSE'; + }); + }; + public slightlyDifferentErrorMessage = () : Promise => { + return Promise.resolve().then(() => { + if (1 < 2) { + return 'SOMETHING'; + } + return 'SOMETHING'; + }); + }; +} + +// Repro from #32349 + +declare function invoke(f: () => T): T; + +let xx: 0 | 1 | 2 = invoke(() => 1); //// [instantiateContextualTypes.js] @@ -162,3 +196,29 @@ var N1; createElement2(InferFunctionTypes, [(foo) => "" + foo]); })(N1 || (N1 = {})); passContentsToFunc(outerBoxOfString, box => box.value); +class Interesting { + constructor() { + this.compiles = () => { + return Promise.resolve().then(() => { + if (1 < 2) { + return 'SOMETHING'; + } + return 'ELSE'; + }); + }; + this.doesnt = () => { + return Promise.resolve().then(() => { + return 'ELSE'; + }); + }; + this.slightlyDifferentErrorMessage = () => { + return Promise.resolve().then(() => { + if (1 < 2) { + return 'SOMETHING'; + } + return 'SOMETHING'; + }); + }; + } +} +let xx = invoke(() => 1); diff --git a/tests/baselines/reference/instantiateContextualTypes.symbols b/tests/baselines/reference/instantiateContextualTypes.symbols index 098be95bac5..1250edd585b 100644 --- a/tests/baselines/reference/instantiateContextualTypes.symbols +++ b/tests/baselines/reference/instantiateContextualTypes.symbols @@ -407,3 +407,77 @@ passContentsToFunc(outerBoxOfString, box => box.value); >box : Symbol(box, Decl(instantiateContextualTypes.ts, 138, 36)) >value : Symbol(value, Decl(instantiateContextualTypes.ts, 121, 20)) +// Repro from #32349 + +type DooDad = 'SOMETHING' | 'ELSE' ; +>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55)) + +class Interesting { +>Interesting : Symbol(Interesting, Decl(instantiateContextualTypes.ts, 142, 36)) + + public compiles = () : Promise => { +>compiles : Symbol(Interesting.compiles, Decl(instantiateContextualTypes.ts, 144, 19)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55)) + + return Promise.resolve().then(() => { +>Promise.resolve().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) + + if (1 < 2) { + return 'SOMETHING'; + } + return 'ELSE'; + }); + }; + public doesnt = () : Promise => { +>doesnt : Symbol(Interesting.doesnt, Decl(instantiateContextualTypes.ts, 152, 3)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55)) + + return Promise.resolve().then(() => { +>Promise.resolve().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) + + return 'ELSE'; + }); + }; + public slightlyDifferentErrorMessage = () : Promise => { +>slightlyDifferentErrorMessage : Symbol(Interesting.slightlyDifferentErrorMessage, Decl(instantiateContextualTypes.ts, 157, 3)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55)) + + return Promise.resolve().then(() => { +>Promise.resolve().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) + + if (1 < 2) { + return 'SOMETHING'; + } + return 'SOMETHING'; + }); + }; +} + +// Repro from #32349 + +declare function invoke(f: () => T): T; +>invoke : Symbol(invoke, Decl(instantiateContextualTypes.ts, 166, 1)) +>T : Symbol(T, Decl(instantiateContextualTypes.ts, 170, 24)) +>f : Symbol(f, Decl(instantiateContextualTypes.ts, 170, 27)) +>T : Symbol(T, Decl(instantiateContextualTypes.ts, 170, 24)) +>T : Symbol(T, Decl(instantiateContextualTypes.ts, 170, 24)) + +let xx: 0 | 1 | 2 = invoke(() => 1); +>xx : Symbol(xx, Decl(instantiateContextualTypes.ts, 172, 3)) +>invoke : Symbol(invoke, Decl(instantiateContextualTypes.ts, 166, 1)) + diff --git a/tests/baselines/reference/instantiateContextualTypes.types b/tests/baselines/reference/instantiateContextualTypes.types index 0e755e82ed3..88e6ca7e4dd 100644 --- a/tests/baselines/reference/instantiateContextualTypes.types +++ b/tests/baselines/reference/instantiateContextualTypes.types @@ -326,3 +326,99 @@ passContentsToFunc(outerBoxOfString, box => box.value); >box : InnerBox >value : string +// Repro from #32349 + +type DooDad = 'SOMETHING' | 'ELSE' ; +>DooDad : DooDad + +class Interesting { +>Interesting : Interesting + + public compiles = () : Promise => { +>compiles : () => Promise +>() : Promise => { return Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'ELSE'; }); } : () => Promise + + return Promise.resolve().then(() => { +>Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'ELSE'; }) : Promise +>Promise.resolve().then : (onfulfilled?: ((value: void) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>Promise.resolve() : Promise +>Promise.resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>Promise : PromiseConstructor +>resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>then : (onfulfilled?: ((value: void) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>() => { if (1 < 2) { return 'SOMETHING'; } return 'ELSE'; } : () => "SOMETHING" | "ELSE" + + if (1 < 2) { +>1 < 2 : boolean +>1 : 1 +>2 : 2 + + return 'SOMETHING'; +>'SOMETHING' : "SOMETHING" + } + return 'ELSE'; +>'ELSE' : "ELSE" + + }); + }; + public doesnt = () : Promise => { +>doesnt : () => Promise +>() : Promise => { return Promise.resolve().then(() => { return 'ELSE'; }); } : () => Promise + + return Promise.resolve().then(() => { +>Promise.resolve().then(() => { return 'ELSE'; }) : Promise +>Promise.resolve().then : (onfulfilled?: ((value: void) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>Promise.resolve() : Promise +>Promise.resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>Promise : PromiseConstructor +>resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>then : (onfulfilled?: ((value: void) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>() => { return 'ELSE'; } : () => "ELSE" + + return 'ELSE'; +>'ELSE' : "ELSE" + + }); + }; + public slightlyDifferentErrorMessage = () : Promise => { +>slightlyDifferentErrorMessage : () => Promise +>() : Promise => { return Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'SOMETHING'; }); } : () => Promise + + return Promise.resolve().then(() => { +>Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'SOMETHING'; }) : Promise +>Promise.resolve().then : (onfulfilled?: ((value: void) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>Promise.resolve() : Promise +>Promise.resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>Promise : PromiseConstructor +>resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>then : (onfulfilled?: ((value: void) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>() => { if (1 < 2) { return 'SOMETHING'; } return 'SOMETHING'; } : () => "SOMETHING" + + if (1 < 2) { +>1 < 2 : boolean +>1 : 1 +>2 : 2 + + return 'SOMETHING'; +>'SOMETHING' : "SOMETHING" + } + return 'SOMETHING'; +>'SOMETHING' : "SOMETHING" + + }); + }; +} + +// Repro from #32349 + +declare function invoke(f: () => T): T; +>invoke : (f: () => T) => T +>f : () => T + +let xx: 0 | 1 | 2 = invoke(() => 1); +>xx : 0 | 1 | 2 +>invoke(() => 1) : 1 +>invoke : (f: () => T) => T +>() => 1 : () => 1 +>1 : 1 + From d8b191a671c9cddd095d52b31c06d89222e5dd77 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 16 Jul 2019 16:29:52 -0700 Subject: [PATCH 04/30] Improve algorithm for inferring to union types --- src/compiler/checker.ts | 51 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06395d935b7..75b12ee37bb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15458,6 +15458,7 @@ namespace ts { let visited: Map; let bivariant = false; let propagationType: Type; + let inferenceCount = 0; let allowComplexConstraintInference = true; inferFromTypes(originalSource, originalTarget); @@ -15561,6 +15562,7 @@ namespace ts { clearCachedInferences(inferences); } } + inferenceCount++; return; } else { @@ -15610,13 +15612,16 @@ namespace ts { inferFromTypes(getTrueTypeFromConditionalType(source), getTrueTypeFromConditionalType(target)); inferFromTypes(getFalseTypeFromConditionalType(source), getFalseTypeFromConditionalType(target)); } + else if (target.flags & TypeFlags.Union) { + inferToUnionType(source, target); + } + else if (target.flags & TypeFlags.Intersection) { + inferToMultipleTypes(source, (target).types, /*isIntersection*/ true); + } else if (target.flags & TypeFlags.Conditional && !contravariant) { const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; inferToMultipleTypes(source, targetTypes, /*isIntersection*/ false); } - else if (target.flags & TypeFlags.UnionOrIntersection) { - inferToMultipleTypes(source, (target).types, !!(target.flags & TypeFlags.Intersection)); - } else if (source.flags & TypeFlags.Union) { // Source is a union or intersection type, infer from each constituent type const sourceTypes = (source).types; @@ -15742,6 +15747,46 @@ namespace ts { } } + function inferToUnionType(source: Type, target: UnionType) { + const sources = source.flags & TypeFlags.Union ? (source).types : [source]; + const matched = new Array(sources.length); + let typeVariableCount = 0; + // First infer to types that are not naked type variables. For each source type we + // track whether inferences were made from that particular type to some target. + for (const t of target.types) { + if (getInferenceInfoForType(t)) { + typeVariableCount++; + } + else { + for (let i = 0; i < sources.length; i++) { + const count = inferenceCount; + inferFromTypes(sources[i], t); + if (count !== inferenceCount) matched[i] = true; + } + } + } + // If there are naked type variables in the target, create a union of the source types + // from which no inferences have been made so far and infer from that union to each naked + // type variable. If there is more than one naked type variable, give lower priority to + // the inferences as they are less specific. + if (typeVariableCount > 0) { + const unmatched = flatMap(sources, (s, i) => matched![i] ? undefined : s); + if (unmatched.length) { + const s = getUnionType(unmatched); + const savePriority = priority; + if (typeVariableCount > 1) { + priority |= InferencePriority.NakedTypeVariable; + } + for (const t of target.types) { + if (getInferenceInfoForType(t)) { + inferFromTypes(s, t); + } + } + priority = savePriority; + } + } + } + function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { if (constraintType.flags & TypeFlags.Union) { let result = false; From 5a45d5aed8dc6b6c47d8ab23cdf161049d812afe Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 14:53:29 -0700 Subject: [PATCH 05/30] Reduce union and intersection targets when source is singleton type --- src/compiler/checker.ts | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 75b12ee37bb..1a2fc79534e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15500,15 +15500,10 @@ namespace ts { // of all their possible values. let matchingTypes: Type[] | undefined; for (const t of (source).types) { - if (typeIdenticalToSomeType(t, (target).types)) { - (matchingTypes || (matchingTypes = [])).push(t); - inferFromTypes(t, t); - } - else if (t.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral)) { - const b = getBaseTypeOfLiteralType(t); - if (typeIdenticalToSomeType(b, (target).types)) { - (matchingTypes || (matchingTypes = [])).push(t, b); - } + const matched = findMatchedType(t, target); + if (matched) { + (matchingTypes || (matchingTypes = [])).push(matched); + inferFromTypes(matched, matched); } } // Next, to improve the quality of inferences, reduce the source and target types by @@ -15519,6 +15514,14 @@ namespace ts { target = removeTypesFromUnionOrIntersection(target, matchingTypes); } } + else if (target.flags & TypeFlags.Union && !(target.flags & TypeFlags.EnumLiteral) || target.flags & TypeFlags.Intersection) { + const matched = findMatchedType(source, target); + if (matched) { + inferFromTypes(matched, matched); + source = target.flags & TypeFlags.Union ? neverType : unknownType; + target = removeTypesFromUnionOrIntersection(target, [matched]); + } + } else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) { target = getActualTypeVariable(target); } @@ -15955,6 +15958,19 @@ namespace ts { return false; } + function findMatchedType(type: Type, target: UnionOrIntersectionType) { + if (typeIdenticalToSomeType(type, target.types)) { + return type; + } + if (type.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral) && target.flags & TypeFlags.Union) { + const base = getBaseTypeOfLiteralType(type); + if (typeIdenticalToSomeType(base, target.types)) { + return base; + } + } + return undefined; + } + /** * Return a new union or intersection type computed by removing a given set of types * from a given union or intersection type. From 652bb1277cd72946fde639479e816933dfd0cbd9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 14:54:27 -0700 Subject: [PATCH 06/30] Accept new baselines --- .../reference/unionAndIntersectionInference2.types | 2 +- .../reference/unionTypeInference.errors.txt | 13 +++++++++---- tests/baselines/reference/unionTypeInference.types | 6 +++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/unionAndIntersectionInference2.types b/tests/baselines/reference/unionAndIntersectionInference2.types index a163b25ce28..031354506b7 100644 --- a/tests/baselines/reference/unionAndIntersectionInference2.types +++ b/tests/baselines/reference/unionAndIntersectionInference2.types @@ -20,7 +20,7 @@ var e1: number | string | boolean; >e1 : string | number | boolean f1(a1); // string ->f1(a1) : string +>f1(a1) : never >f1 : (x: string | T) => T >a1 : string diff --git a/tests/baselines/reference/unionTypeInference.errors.txt b/tests/baselines/reference/unionTypeInference.errors.txt index dfda0d57c2b..ec5c0e11f8d 100644 --- a/tests/baselines/reference/unionTypeInference.errors.txt +++ b/tests/baselines/reference/unionTypeInference.errors.txt @@ -1,7 +1,8 @@ -tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(9,15): error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'. +tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a3' must be of type 'number', but here has type 'string | number'. +tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c2' must be of type 'string', but here has type 'never'. -==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (1 errors) ==== +==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (2 errors) ==== // Verify that inferences made *to* a type parameter in a union type are secondary // to inferences made directly to that type parameter @@ -11,12 +12,13 @@ tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference var a1: number; var a1 = f(1, 2); - ~ -!!! error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'. var a2: number; var a2 = f(1, "hello"); var a3: number; var a3 = f(1, a1 || "hello"); + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a3' must be of type 'number', but here has type 'string | number'. +!!! related TS6203 tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts:12:5: 'a3' was also declared here. var a4: any; var a4 = f(undefined, "abc"); @@ -35,4 +37,7 @@ tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference var c1 = h(5); var c2: string; var c2 = h("abc"); + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c2' must be of type 'string', but here has type 'never'. +!!! related TS6203 tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts:30:5: 'c2' was also declared here. \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeInference.types b/tests/baselines/reference/unionTypeInference.types index e712916c2ff..fc5b777ff5a 100644 --- a/tests/baselines/reference/unionTypeInference.types +++ b/tests/baselines/reference/unionTypeInference.types @@ -16,7 +16,7 @@ var a1: number; var a1 = f(1, 2); >a1 : number ->f(1, 2) : any +>f(1, 2) : 1 | 2 >f : (x: T, y: string | T) => T >1 : 1 >2 : 2 @@ -36,7 +36,7 @@ var a3: number; var a3 = f(1, a1 || "hello"); >a3 : number ->f(1, a1 || "hello") : number +>f(1, a1 || "hello") : number | "hello" >f : (x: T, y: string | T) => T >1 : 1 >a1 || "hello" : number | "hello" @@ -107,7 +107,7 @@ var c2: string; var c2 = h("abc"); >c2 : string ->h("abc") : "abc" +>h("abc") : never >h : (x: string | boolean | T) => T >"abc" : "abc" From 7d4259ba9fa4cfa039c36cc54aa5f1351aa36760 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 14:57:26 -0700 Subject: [PATCH 07/30] Update tests --- .../typeInference/unionTypeInference.ts | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts b/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts index 39def706622..14ce8e91fc7 100644 --- a/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts +++ b/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts @@ -1,31 +1,42 @@ -// Verify that inferences made *to* a type parameter in a union type are secondary -// to inferences made directly to that type parameter +// @strict: true -function f(x: T, y: string|T): T { - return x; -} +declare const b: boolean; +declare const s: string; +declare const sn: string | number; -var a1: number; -var a1 = f(1, 2); -var a2: number; -var a2 = f(1, "hello"); -var a3: number; -var a3 = f(1, a1 || "hello"); -var a4: any; -var a4 = f(undefined, "abc"); +declare function f1(x: T, y: string | T): T; -function g(value: [string, T]): T { - return value[1]; -} +const a1 = f1(1, 2); // 1 | 2 +const a2 = f1(1, "hello"); // 1 +const a3 = f1(1, sn); // number +const a4 = f1(undefined, "abc"); // undefined +const a5 = f1("foo", "bar"); // "foo" +const a6 = f1(true, false); // boolean +const a7 = f1("hello", 1); // Error -var b1: boolean; -var b1 = g(["string", true]); +declare function f2(value: [string, T]): T; -function h(x: string|boolean|T): T { - return typeof x === "string" || typeof x === "boolean" ? undefined : x; -} +var b1 = f2(["string", true]); // boolean -var c1: number; -var c1 = h(5); -var c2: string; -var c2 = h("abc"); +declare function f3(x: string | false | T): T; + +const c1 = f3(5); // 5 +const c2 = f3(sn); // number +const c3 = f3(true); // true +const c4 = f3(b); // true +const c5 = f3("abc"); // never + +declare function f4(x: string & T): T; + +var d1 = f4("abc"); +var d2 = f4(s); +var d3 = f4(42); // Error + +// Repros from #32434 + +declare function foo(x: T | Promise): void; +declare let x: false | Promise; +foo(x); + +declare function bar(x: T, y: string | T): T; +const y = bar(1, 2); From ae1add72104b6e3ca7a8e765af77f3bec9003ce6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 15:02:20 -0700 Subject: [PATCH 08/30] Update tests --- .../typeRelationships/typeInference/unionTypeInference.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts b/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts index 14ce8e91fc7..ccedb753354 100644 --- a/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts +++ b/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts @@ -28,9 +28,9 @@ const c5 = f3("abc"); // never declare function f4(x: string & T): T; -var d1 = f4("abc"); -var d2 = f4(s); -var d3 = f4(42); // Error +const d1 = f4("abc"); +const d2 = f4(s); +const d3 = f4(42); // Error // Repros from #32434 From c4bad6443884ee7218f1b970784f2c03e23d52bb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 15:03:15 -0700 Subject: [PATCH 09/30] Accept new baselines --- .../reference/unionTypeInference.errors.txt | 73 +++--- .../baselines/reference/unionTypeInference.js | 103 ++++----- .../reference/unionTypeInference.symbols | 194 ++++++++++------ .../reference/unionTypeInference.types | 210 +++++++++++------- 4 files changed, 342 insertions(+), 238 deletions(-) diff --git a/tests/baselines/reference/unionTypeInference.errors.txt b/tests/baselines/reference/unionTypeInference.errors.txt index ec5c0e11f8d..6993f4280a7 100644 --- a/tests/baselines/reference/unionTypeInference.errors.txt +++ b/tests/baselines/reference/unionTypeInference.errors.txt @@ -1,43 +1,50 @@ -tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a3' must be of type 'number', but here has type 'string | number'. -tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c2' must be of type 'string', but here has type 'never'. +tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,24): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'. +tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,13): error TS2345: Argument of type '42' is not assignable to parameter of type 'never'. ==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (2 errors) ==== - // Verify that inferences made *to* a type parameter in a union type are secondary - // to inferences made directly to that type parameter + declare const b: boolean; + declare const s: string; + declare const sn: string | number; - function f(x: T, y: string|T): T { - return x; - } + declare function f1(x: T, y: string | T): T; - var a1: number; - var a1 = f(1, 2); - var a2: number; - var a2 = f(1, "hello"); - var a3: number; - var a3 = f(1, a1 || "hello"); - ~~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a3' must be of type 'number', but here has type 'string | number'. -!!! related TS6203 tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts:12:5: 'a3' was also declared here. - var a4: any; - var a4 = f(undefined, "abc"); + const a1 = f1(1, 2); // 1 | 2 + const a2 = f1(1, "hello"); // 1 + const a3 = f1(1, sn); // number + const a4 = f1(undefined, "abc"); // undefined + const a5 = f1("foo", "bar"); // "foo" + const a6 = f1(true, false); // boolean + const a7 = f1("hello", 1); // Error + ~ +!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'string'. - function g(value: [string, T]): T { - return value[1]; - } + declare function f2(value: [string, T]): T; - var b1: boolean; - var b1 = g(["string", true]); + var b1 = f2(["string", true]); // boolean - function h(x: string|boolean|T): T { - return typeof x === "string" || typeof x === "boolean" ? undefined : x; - } + declare function f3(x: string | false | T): T; - var c1: number; - var c1 = h(5); - var c2: string; - var c2 = h("abc"); - ~~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c2' must be of type 'string', but here has type 'never'. -!!! related TS6203 tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts:30:5: 'c2' was also declared here. + const c1 = f3(5); // 5 + const c2 = f3(sn); // number + const c3 = f3(true); // true + const c4 = f3(b); // true + const c5 = f3("abc"); // never + + declare function f4(x: string & T): T; + + var d1 = f4("abc"); + var d2 = f4(s); + var d3 = f4(42); // Error + ~~ +!!! error TS2345: Argument of type '42' is not assignable to parameter of type 'never'. + + // Repros from #32434 + + declare function foo(x: T | Promise): void; + declare let x: false | Promise; + foo(x); + + declare function bar(x: T, y: string | T): T; + const y = bar(1, 2); \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeInference.js b/tests/baselines/reference/unionTypeInference.js index bdaa340f6ea..fb94e1910f1 100644 --- a/tests/baselines/reference/unionTypeInference.js +++ b/tests/baselines/reference/unionTypeInference.js @@ -1,60 +1,63 @@ //// [unionTypeInference.ts] -// Verify that inferences made *to* a type parameter in a union type are secondary -// to inferences made directly to that type parameter +declare const b: boolean; +declare const s: string; +declare const sn: string | number; -function f(x: T, y: string|T): T { - return x; -} +declare function f1(x: T, y: string | T): T; -var a1: number; -var a1 = f(1, 2); -var a2: number; -var a2 = f(1, "hello"); -var a3: number; -var a3 = f(1, a1 || "hello"); -var a4: any; -var a4 = f(undefined, "abc"); +const a1 = f1(1, 2); // 1 | 2 +const a2 = f1(1, "hello"); // 1 +const a3 = f1(1, sn); // number +const a4 = f1(undefined, "abc"); // undefined +const a5 = f1("foo", "bar"); // "foo" +const a6 = f1(true, false); // boolean +const a7 = f1("hello", 1); // Error -function g(value: [string, T]): T { - return value[1]; -} +declare function f2(value: [string, T]): T; -var b1: boolean; -var b1 = g(["string", true]); +var b1 = f2(["string", true]); // boolean -function h(x: string|boolean|T): T { - return typeof x === "string" || typeof x === "boolean" ? undefined : x; -} +declare function f3(x: string | false | T): T; -var c1: number; -var c1 = h(5); -var c2: string; -var c2 = h("abc"); +const c1 = f3(5); // 5 +const c2 = f3(sn); // number +const c3 = f3(true); // true +const c4 = f3(b); // true +const c5 = f3("abc"); // never + +declare function f4(x: string & T): T; + +var d1 = f4("abc"); +var d2 = f4(s); +var d3 = f4(42); // Error + +// Repros from #32434 + +declare function foo(x: T | Promise): void; +declare let x: false | Promise; +foo(x); + +declare function bar(x: T, y: string | T): T; +const y = bar(1, 2); //// [unionTypeInference.js] -// Verify that inferences made *to* a type parameter in a union type are secondary -// to inferences made directly to that type parameter -function f(x, y) { - return x; -} -var a1; -var a1 = f(1, 2); -var a2; -var a2 = f(1, "hello"); -var a3; -var a3 = f(1, a1 || "hello"); -var a4; -var a4 = f(undefined, "abc"); -function g(value) { - return value[1]; -} -var b1; -var b1 = g(["string", true]); -function h(x) { - return typeof x === "string" || typeof x === "boolean" ? undefined : x; -} -var c1; -var c1 = h(5); -var c2; -var c2 = h("abc"); +"use strict"; +var a1 = f1(1, 2); // 1 | 2 +var a2 = f1(1, "hello"); // 1 +var a3 = f1(1, sn); // number +var a4 = f1(undefined, "abc"); // undefined +var a5 = f1("foo", "bar"); // "foo" +var a6 = f1(true, false); // boolean +var a7 = f1("hello", 1); // Error +var b1 = f2(["string", true]); // boolean +var c1 = f3(5); // 5 +var c2 = f3(sn); // number +var c3 = f3(true); // true +var c4 = f3(b); // true +var c5 = f3("abc"); // never +var d1 = f4("abc"); +var d2 = f4(s); +var d3 = f4(42); // Error +foo(x); +var y = bar(1, 2); diff --git a/tests/baselines/reference/unionTypeInference.symbols b/tests/baselines/reference/unionTypeInference.symbols index 3388f279f4b..a34be279837 100644 --- a/tests/baselines/reference/unionTypeInference.symbols +++ b/tests/baselines/reference/unionTypeInference.symbols @@ -1,94 +1,140 @@ === tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts === -// Verify that inferences made *to* a type parameter in a union type are secondary -// to inferences made directly to that type parameter +declare const b: boolean; +>b : Symbol(b, Decl(unionTypeInference.ts, 0, 13)) -function f(x: T, y: string|T): T { ->f : Symbol(f, Decl(unionTypeInference.ts, 0, 0)) ->T : Symbol(T, Decl(unionTypeInference.ts, 3, 11)) ->x : Symbol(x, Decl(unionTypeInference.ts, 3, 14)) ->T : Symbol(T, Decl(unionTypeInference.ts, 3, 11)) ->y : Symbol(y, Decl(unionTypeInference.ts, 3, 19)) ->T : Symbol(T, Decl(unionTypeInference.ts, 3, 11)) ->T : Symbol(T, Decl(unionTypeInference.ts, 3, 11)) +declare const s: string; +>s : Symbol(s, Decl(unionTypeInference.ts, 1, 13)) - return x; ->x : Symbol(x, Decl(unionTypeInference.ts, 3, 14)) -} +declare const sn: string | number; +>sn : Symbol(sn, Decl(unionTypeInference.ts, 2, 13)) -var a1: number; ->a1 : Symbol(a1, Decl(unionTypeInference.ts, 7, 3), Decl(unionTypeInference.ts, 8, 3)) +declare function f1(x: T, y: string | T): T; +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) +>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20)) +>x : Symbol(x, Decl(unionTypeInference.ts, 4, 23)) +>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20)) +>y : Symbol(y, Decl(unionTypeInference.ts, 4, 28)) +>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20)) +>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20)) -var a1 = f(1, 2); ->a1 : Symbol(a1, Decl(unionTypeInference.ts, 7, 3), Decl(unionTypeInference.ts, 8, 3)) ->f : Symbol(f, Decl(unionTypeInference.ts, 0, 0)) +const a1 = f1(1, 2); // 1 | 2 +>a1 : Symbol(a1, Decl(unionTypeInference.ts, 6, 5)) +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) -var a2: number; ->a2 : Symbol(a2, Decl(unionTypeInference.ts, 9, 3), Decl(unionTypeInference.ts, 10, 3)) +const a2 = f1(1, "hello"); // 1 +>a2 : Symbol(a2, Decl(unionTypeInference.ts, 7, 5)) +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) -var a2 = f(1, "hello"); ->a2 : Symbol(a2, Decl(unionTypeInference.ts, 9, 3), Decl(unionTypeInference.ts, 10, 3)) ->f : Symbol(f, Decl(unionTypeInference.ts, 0, 0)) +const a3 = f1(1, sn); // number +>a3 : Symbol(a3, Decl(unionTypeInference.ts, 8, 5)) +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) +>sn : Symbol(sn, Decl(unionTypeInference.ts, 2, 13)) -var a3: number; ->a3 : Symbol(a3, Decl(unionTypeInference.ts, 11, 3), Decl(unionTypeInference.ts, 12, 3)) - -var a3 = f(1, a1 || "hello"); ->a3 : Symbol(a3, Decl(unionTypeInference.ts, 11, 3), Decl(unionTypeInference.ts, 12, 3)) ->f : Symbol(f, Decl(unionTypeInference.ts, 0, 0)) ->a1 : Symbol(a1, Decl(unionTypeInference.ts, 7, 3), Decl(unionTypeInference.ts, 8, 3)) - -var a4: any; ->a4 : Symbol(a4, Decl(unionTypeInference.ts, 13, 3), Decl(unionTypeInference.ts, 14, 3)) - -var a4 = f(undefined, "abc"); ->a4 : Symbol(a4, Decl(unionTypeInference.ts, 13, 3), Decl(unionTypeInference.ts, 14, 3)) ->f : Symbol(f, Decl(unionTypeInference.ts, 0, 0)) +const a4 = f1(undefined, "abc"); // undefined +>a4 : Symbol(a4, Decl(unionTypeInference.ts, 9, 5)) +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) >undefined : Symbol(undefined) -function g(value: [string, T]): T { ->g : Symbol(g, Decl(unionTypeInference.ts, 14, 29)) ->T : Symbol(T, Decl(unionTypeInference.ts, 16, 11)) ->value : Symbol(value, Decl(unionTypeInference.ts, 16, 14)) ->T : Symbol(T, Decl(unionTypeInference.ts, 16, 11)) ->T : Symbol(T, Decl(unionTypeInference.ts, 16, 11)) +const a5 = f1("foo", "bar"); // "foo" +>a5 : Symbol(a5, Decl(unionTypeInference.ts, 10, 5)) +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) - return value[1]; ->value : Symbol(value, Decl(unionTypeInference.ts, 16, 14)) ->1 : Symbol(1) -} +const a6 = f1(true, false); // boolean +>a6 : Symbol(a6, Decl(unionTypeInference.ts, 11, 5)) +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) -var b1: boolean; ->b1 : Symbol(b1, Decl(unionTypeInference.ts, 20, 3), Decl(unionTypeInference.ts, 21, 3)) +const a7 = f1("hello", 1); // Error +>a7 : Symbol(a7, Decl(unionTypeInference.ts, 12, 5)) +>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34)) -var b1 = g(["string", true]); ->b1 : Symbol(b1, Decl(unionTypeInference.ts, 20, 3), Decl(unionTypeInference.ts, 21, 3)) ->g : Symbol(g, Decl(unionTypeInference.ts, 14, 29)) +declare function f2(value: [string, T]): T; +>f2 : Symbol(f2, Decl(unionTypeInference.ts, 12, 26)) +>T : Symbol(T, Decl(unionTypeInference.ts, 14, 20)) +>value : Symbol(value, Decl(unionTypeInference.ts, 14, 23)) +>T : Symbol(T, Decl(unionTypeInference.ts, 14, 20)) +>T : Symbol(T, Decl(unionTypeInference.ts, 14, 20)) -function h(x: string|boolean|T): T { ->h : Symbol(h, Decl(unionTypeInference.ts, 21, 29)) ->T : Symbol(T, Decl(unionTypeInference.ts, 23, 11)) ->x : Symbol(x, Decl(unionTypeInference.ts, 23, 14)) ->T : Symbol(T, Decl(unionTypeInference.ts, 23, 11)) ->T : Symbol(T, Decl(unionTypeInference.ts, 23, 11)) +var b1 = f2(["string", true]); // boolean +>b1 : Symbol(b1, Decl(unionTypeInference.ts, 16, 3)) +>f2 : Symbol(f2, Decl(unionTypeInference.ts, 12, 26)) - return typeof x === "string" || typeof x === "boolean" ? undefined : x; ->x : Symbol(x, Decl(unionTypeInference.ts, 23, 14)) ->x : Symbol(x, Decl(unionTypeInference.ts, 23, 14)) ->undefined : Symbol(undefined) ->x : Symbol(x, Decl(unionTypeInference.ts, 23, 14)) -} +declare function f3(x: string | false | T): T; +>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30)) +>T : Symbol(T, Decl(unionTypeInference.ts, 18, 20)) +>x : Symbol(x, Decl(unionTypeInference.ts, 18, 23)) +>T : Symbol(T, Decl(unionTypeInference.ts, 18, 20)) +>T : Symbol(T, Decl(unionTypeInference.ts, 18, 20)) -var c1: number; ->c1 : Symbol(c1, Decl(unionTypeInference.ts, 27, 3), Decl(unionTypeInference.ts, 28, 3)) +const c1 = f3(5); // 5 +>c1 : Symbol(c1, Decl(unionTypeInference.ts, 20, 5)) +>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30)) -var c1 = h(5); ->c1 : Symbol(c1, Decl(unionTypeInference.ts, 27, 3), Decl(unionTypeInference.ts, 28, 3)) ->h : Symbol(h, Decl(unionTypeInference.ts, 21, 29)) +const c2 = f3(sn); // number +>c2 : Symbol(c2, Decl(unionTypeInference.ts, 21, 5)) +>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30)) +>sn : Symbol(sn, Decl(unionTypeInference.ts, 2, 13)) -var c2: string; ->c2 : Symbol(c2, Decl(unionTypeInference.ts, 29, 3), Decl(unionTypeInference.ts, 30, 3)) +const c3 = f3(true); // true +>c3 : Symbol(c3, Decl(unionTypeInference.ts, 22, 5)) +>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30)) -var c2 = h("abc"); ->c2 : Symbol(c2, Decl(unionTypeInference.ts, 29, 3), Decl(unionTypeInference.ts, 30, 3)) ->h : Symbol(h, Decl(unionTypeInference.ts, 21, 29)) +const c4 = f3(b); // true +>c4 : Symbol(c4, Decl(unionTypeInference.ts, 23, 5)) +>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30)) +>b : Symbol(b, Decl(unionTypeInference.ts, 0, 13)) + +const c5 = f3("abc"); // never +>c5 : Symbol(c5, Decl(unionTypeInference.ts, 24, 5)) +>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30)) + +declare function f4(x: string & T): T; +>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) +>T : Symbol(T, Decl(unionTypeInference.ts, 26, 20)) +>x : Symbol(x, Decl(unionTypeInference.ts, 26, 23)) +>T : Symbol(T, Decl(unionTypeInference.ts, 26, 20)) +>T : Symbol(T, Decl(unionTypeInference.ts, 26, 20)) + +var d1 = f4("abc"); +>d1 : Symbol(d1, Decl(unionTypeInference.ts, 28, 3)) +>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) + +var d2 = f4(s); +>d2 : Symbol(d2, Decl(unionTypeInference.ts, 29, 3)) +>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) +>s : Symbol(s, Decl(unionTypeInference.ts, 1, 13)) + +var d3 = f4(42); // Error +>d3 : Symbol(d3, Decl(unionTypeInference.ts, 30, 3)) +>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) + +// Repros from #32434 + +declare function foo(x: T | Promise): void; +>foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 16)) +>T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) +>x : Symbol(x, Decl(unionTypeInference.ts, 34, 24)) +>T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) + +declare let x: false | Promise; +>x : Symbol(x, Decl(unionTypeInference.ts, 35, 11)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + +foo(x); +>foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 16)) +>x : Symbol(x, Decl(unionTypeInference.ts, 35, 11)) + +declare function bar(x: T, y: string | T): T; +>bar : Symbol(bar, Decl(unionTypeInference.ts, 36, 7)) +>T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) +>x : Symbol(x, Decl(unionTypeInference.ts, 38, 24)) +>T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) +>y : Symbol(y, Decl(unionTypeInference.ts, 38, 29)) +>T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) +>T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) + +const y = bar(1, 2); +>y : Symbol(y, Decl(unionTypeInference.ts, 39, 5)) +>bar : Symbol(bar, Decl(unionTypeInference.ts, 36, 7)) diff --git a/tests/baselines/reference/unionTypeInference.types b/tests/baselines/reference/unionTypeInference.types index fc5b777ff5a..836c298bdbc 100644 --- a/tests/baselines/reference/unionTypeInference.types +++ b/tests/baselines/reference/unionTypeInference.types @@ -1,113 +1,161 @@ === tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts === -// Verify that inferences made *to* a type parameter in a union type are secondary -// to inferences made directly to that type parameter +declare const b: boolean; +>b : boolean -function f(x: T, y: string|T): T { ->f : (x: T, y: string | T) => T +declare const s: string; +>s : string + +declare const sn: string | number; +>sn : string | number + +declare function f1(x: T, y: string | T): T; +>f1 : (x: T, y: string | T) => T >x : T >y : string | T - return x; ->x : T -} - -var a1: number; ->a1 : number - -var a1 = f(1, 2); ->a1 : number ->f(1, 2) : 1 | 2 ->f : (x: T, y: string | T) => T +const a1 = f1(1, 2); // 1 | 2 +>a1 : 1 | 2 +>f1(1, 2) : 1 | 2 +>f1 : (x: T, y: string | T) => T >1 : 1 >2 : 2 -var a2: number; ->a2 : number - -var a2 = f(1, "hello"); ->a2 : number ->f(1, "hello") : 1 ->f : (x: T, y: string | T) => T +const a2 = f1(1, "hello"); // 1 +>a2 : 1 +>f1(1, "hello") : 1 +>f1 : (x: T, y: string | T) => T >1 : 1 >"hello" : "hello" -var a3: number; +const a3 = f1(1, sn); // number >a3 : number - -var a3 = f(1, a1 || "hello"); ->a3 : number ->f(1, a1 || "hello") : number | "hello" ->f : (x: T, y: string | T) => T +>f1(1, sn) : number +>f1 : (x: T, y: string | T) => T >1 : 1 ->a1 || "hello" : number | "hello" ->a1 : number ->"hello" : "hello" +>sn : string | number -var a4: any; ->a4 : any - -var a4 = f(undefined, "abc"); ->a4 : any ->f(undefined, "abc") : any ->f : (x: T, y: string | T) => T +const a4 = f1(undefined, "abc"); // undefined +>a4 : undefined +>f1(undefined, "abc") : undefined +>f1 : (x: T, y: string | T) => T >undefined : undefined >"abc" : "abc" -function g(value: [string, T]): T { ->g : (value: [string, T]) => T ->value : [string, T] +const a5 = f1("foo", "bar"); // "foo" +>a5 : "foo" +>f1("foo", "bar") : "foo" +>f1 : (x: T, y: string | T) => T +>"foo" : "foo" +>"bar" : "bar" - return value[1]; ->value[1] : T ->value : [string, T] +const a6 = f1(true, false); // boolean +>a6 : boolean +>f1(true, false) : boolean +>f1 : (x: T, y: string | T) => T +>true : true +>false : false + +const a7 = f1("hello", 1); // Error +>a7 : any +>f1("hello", 1) : any +>f1 : (x: T, y: string | T) => T +>"hello" : "hello" >1 : 1 -} -var b1: boolean; ->b1 : boolean +declare function f2(value: [string, T]): T; +>f2 : (value: [string, T]) => T +>value : [string, T] -var b1 = g(["string", true]); +var b1 = f2(["string", true]); // boolean >b1 : boolean ->g(["string", true]) : boolean ->g : (value: [string, T]) => T +>f2(["string", true]) : boolean +>f2 : (value: [string, T]) => T >["string", true] : [string, true] >"string" : "string" >true : true -function h(x: string|boolean|T): T { ->h : (x: string | boolean | T) => T ->x : string | boolean | T +declare function f3(x: string | false | T): T; +>f3 : (x: string | false | T) => T +>x : string | false | T +>false : false - return typeof x === "string" || typeof x === "boolean" ? undefined : x; ->typeof x === "string" || typeof x === "boolean" ? undefined : x : T ->typeof x === "string" || typeof x === "boolean" : boolean ->typeof x === "string" : boolean ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : string | boolean | T ->"string" : "string" ->typeof x === "boolean" : boolean ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : boolean | T ->"boolean" : "boolean" ->undefined : undefined ->x : T -} - -var c1: number; ->c1 : number - -var c1 = h(5); ->c1 : number ->h(5) : 5 ->h : (x: string | boolean | T) => T +const c1 = f3(5); // 5 +>c1 : 5 +>f3(5) : 5 +>f3 : (x: string | false | T) => T >5 : 5 -var c2: string; ->c2 : string +const c2 = f3(sn); // number +>c2 : number +>f3(sn) : number +>f3 : (x: string | false | T) => T +>sn : string | number -var c2 = h("abc"); ->c2 : string ->h("abc") : never ->h : (x: string | boolean | T) => T +const c3 = f3(true); // true +>c3 : true +>f3(true) : true +>f3 : (x: string | false | T) => T +>true : true + +const c4 = f3(b); // true +>c4 : true +>f3(b) : true +>f3 : (x: string | false | T) => T +>b : boolean + +const c5 = f3("abc"); // never +>c5 : never +>f3("abc") : never +>f3 : (x: string | false | T) => T >"abc" : "abc" +declare function f4(x: string & T): T; +>f4 : (x: string & T) => T +>x : string & T + +var d1 = f4("abc"); +>d1 : string +>f4("abc") : "abc" +>f4 : (x: string & T) => T +>"abc" : "abc" + +var d2 = f4(s); +>d2 : unknown +>f4(s) : unknown +>f4 : (x: string & T) => T +>s : string + +var d3 = f4(42); // Error +>d3 : any +>f4(42) : any +>f4 : (x: string & T) => T +>42 : 42 + +// Repros from #32434 + +declare function foo(x: T | Promise): void; +>foo : (x: T | Promise) => void +>x : T | Promise + +declare let x: false | Promise; +>x : false | Promise +>false : false +>true : true + +foo(x); +>foo(x) : void +>foo : (x: T | Promise) => void +>x : false | Promise + +declare function bar(x: T, y: string | T): T; +>bar : (x: T, y: string | T) => T +>x : T +>y : string | T + +const y = bar(1, 2); +>y : 1 | 2 +>bar(1, 2) : 1 | 2 +>bar : (x: T, y: string | T) => T +>1 : 1 +>2 : 2 + From de837ed51f8f6f329cee97932bf3a8e7ea4cc46e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 15:07:36 -0700 Subject: [PATCH 10/30] Accept new baselines --- .../reference/unionTypeInference.errors.txt | 10 +++++----- tests/baselines/reference/unionTypeInference.js | 6 +++--- .../reference/unionTypeInference.symbols | 16 ++++++++-------- .../baselines/reference/unionTypeInference.types | 8 ++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/baselines/reference/unionTypeInference.errors.txt b/tests/baselines/reference/unionTypeInference.errors.txt index 6993f4280a7..2fe480d0a07 100644 --- a/tests/baselines/reference/unionTypeInference.errors.txt +++ b/tests/baselines/reference/unionTypeInference.errors.txt @@ -1,5 +1,5 @@ tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,24): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'. -tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,13): error TS2345: Argument of type '42' is not assignable to parameter of type 'never'. +tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,15): error TS2345: Argument of type '42' is not assignable to parameter of type 'never'. ==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (2 errors) ==== @@ -33,10 +33,10 @@ tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference declare function f4(x: string & T): T; - var d1 = f4("abc"); - var d2 = f4(s); - var d3 = f4(42); // Error - ~~ + const d1 = f4("abc"); + const d2 = f4(s); + const d3 = f4(42); // Error + ~~ !!! error TS2345: Argument of type '42' is not assignable to parameter of type 'never'. // Repros from #32434 diff --git a/tests/baselines/reference/unionTypeInference.js b/tests/baselines/reference/unionTypeInference.js index fb94e1910f1..868140e83a0 100644 --- a/tests/baselines/reference/unionTypeInference.js +++ b/tests/baselines/reference/unionTypeInference.js @@ -27,9 +27,9 @@ const c5 = f3("abc"); // never declare function f4(x: string & T): T; -var d1 = f4("abc"); -var d2 = f4(s); -var d3 = f4(42); // Error +const d1 = f4("abc"); +const d2 = f4(s); +const d3 = f4(42); // Error // Repros from #32434 diff --git a/tests/baselines/reference/unionTypeInference.symbols b/tests/baselines/reference/unionTypeInference.symbols index a34be279837..52b8809dee6 100644 --- a/tests/baselines/reference/unionTypeInference.symbols +++ b/tests/baselines/reference/unionTypeInference.symbols @@ -94,23 +94,23 @@ declare function f4(x: string & T): T; >T : Symbol(T, Decl(unionTypeInference.ts, 26, 20)) >T : Symbol(T, Decl(unionTypeInference.ts, 26, 20)) -var d1 = f4("abc"); ->d1 : Symbol(d1, Decl(unionTypeInference.ts, 28, 3)) +const d1 = f4("abc"); +>d1 : Symbol(d1, Decl(unionTypeInference.ts, 28, 5)) >f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) -var d2 = f4(s); ->d2 : Symbol(d2, Decl(unionTypeInference.ts, 29, 3)) +const d2 = f4(s); +>d2 : Symbol(d2, Decl(unionTypeInference.ts, 29, 5)) >f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) >s : Symbol(s, Decl(unionTypeInference.ts, 1, 13)) -var d3 = f4(42); // Error ->d3 : Symbol(d3, Decl(unionTypeInference.ts, 30, 3)) +const d3 = f4(42); // Error +>d3 : Symbol(d3, Decl(unionTypeInference.ts, 30, 5)) >f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) // Repros from #32434 declare function foo(x: T | Promise): void; ->foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 16)) +>foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 18)) >T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) >x : Symbol(x, Decl(unionTypeInference.ts, 34, 24)) >T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) @@ -122,7 +122,7 @@ declare let x: false | Promise; >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) foo(x); ->foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 16)) +>foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 18)) >x : Symbol(x, Decl(unionTypeInference.ts, 35, 11)) declare function bar(x: T, y: string | T): T; diff --git a/tests/baselines/reference/unionTypeInference.types b/tests/baselines/reference/unionTypeInference.types index 836c298bdbc..e6d47fa4bda 100644 --- a/tests/baselines/reference/unionTypeInference.types +++ b/tests/baselines/reference/unionTypeInference.types @@ -113,19 +113,19 @@ declare function f4(x: string & T): T; >f4 : (x: string & T) => T >x : string & T -var d1 = f4("abc"); ->d1 : string +const d1 = f4("abc"); +>d1 : "abc" >f4("abc") : "abc" >f4 : (x: string & T) => T >"abc" : "abc" -var d2 = f4(s); +const d2 = f4(s); >d2 : unknown >f4(s) : unknown >f4 : (x: string & T) => T >s : string -var d3 = f4(42); // Error +const d3 = f4(42); // Error >d3 : any >f4(42) : any >f4 : (x: string & T) => T From c6b77fa5dfe9a396c24035ed77a947c81a1ba42f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 15:15:56 -0700 Subject: [PATCH 11/30] Fix lint error --- 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 1a2fc79534e..81c2a9590ba 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15773,7 +15773,7 @@ namespace ts { // type variable. If there is more than one naked type variable, give lower priority to // the inferences as they are less specific. if (typeVariableCount > 0) { - const unmatched = flatMap(sources, (s, i) => matched![i] ? undefined : s); + const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); if (unmatched.length) { const s = getUnionType(unmatched); const savePriority = priority; From 8f020559fbde9d0c8252a3fde5dc4f2890461fb0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Jul 2019 18:49:56 -0700 Subject: [PATCH 12/30] Treat Array and ReadonlyArray as synonymous in inference --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 81c2a9590ba..f044ee8e375 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15587,7 +15587,8 @@ namespace ts { } } } - if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( + (source).target === (target).target || isArrayType(source) && isArrayType(target))) { // If source and target are references to the same generic type, infer from type arguments inferFromTypeArguments((source).typeArguments || emptyArray, (target).typeArguments || emptyArray, getVariances((source).target)); } From 2450c1947facf8101cb6cba2e030877ec28a0a88 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jul 2019 09:57:10 -0700 Subject: [PATCH 13/30] Make lower priority inferences when inference process is blocked --- src/compiler/checker.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f044ee8e375..c2510f84a19 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15459,6 +15459,7 @@ namespace ts { let bivariant = false; let propagationType: Type; let inferenceCount = 0; + let inferenceBlocked = false; let allowComplexConstraintInference = true; inferFromTypes(originalSource, originalTarget); @@ -15655,6 +15656,7 @@ namespace ts { if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { const key = source.id + "," + target.id; if (visited && visited.get(key)) { + inferenceBlocked = true; return; } (visited || (visited = createMap())).set(key, true); @@ -15667,6 +15669,7 @@ namespace ts { const symbol = isNonConstructorObject ? target.symbol : undefined; if (symbol) { if (contains(symbolStack, symbol)) { + inferenceBlocked = true; return; } (symbolStack || (symbolStack = [])).push(symbol); @@ -15755,6 +15758,8 @@ namespace ts { const sources = source.flags & TypeFlags.Union ? (source).types : [source]; const matched = new Array(sources.length); let typeVariableCount = 0; + const saveInferenceBlocked = inferenceBlocked; + inferenceBlocked = false; // First infer to types that are not naked type variables. For each source type we // track whether inferences were made from that particular type to some target. for (const t of target.types) { @@ -15771,14 +15776,15 @@ namespace ts { } // If there are naked type variables in the target, create a union of the source types // from which no inferences have been made so far and infer from that union to each naked - // type variable. If there is more than one naked type variable, give lower priority to - // the inferences as they are less specific. + // type variable. If there is more than one naked type variable, or if inference was blocked + // (meaning we didn't explore the types fully), give lower priority to the inferences as + // they are less specific. if (typeVariableCount > 0) { const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); if (unmatched.length) { const s = getUnionType(unmatched); const savePriority = priority; - if (typeVariableCount > 1) { + if (typeVariableCount > 1 || inferenceBlocked) { priority |= InferencePriority.NakedTypeVariable; } for (const t of target.types) { @@ -15789,6 +15795,7 @@ namespace ts { priority = savePriority; } } + inferenceBlocked = saveInferenceBlocked; } function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { From d96d16e10b1c307719314886a2a740735593a2e8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jul 2019 10:01:59 -0700 Subject: [PATCH 14/30] Add additional test --- .../typeInference/unionTypeInference.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts b/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts index ccedb753354..4d9a3eae21e 100644 --- a/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts +++ b/tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts @@ -32,6 +32,17 @@ const d1 = f4("abc"); const d2 = f4(s); const d3 = f4(42); // Error +export interface Foo { + then(f: (x: T) => U | Foo, g: U): Foo; +} +export interface Bar { + then(f: (x: T) => S | Bar, g: S): Bar; +} + +function qux(p1: Foo, p2: Bar) { + p1 = p2; +} + // Repros from #32434 declare function foo(x: T | Promise): void; From 623a1725c8f7ae779eb754a0d5d9f29a7e633688 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jul 2019 10:02:46 -0700 Subject: [PATCH 15/30] Accept new baselines --- .../reference/unionTypeInference.errors.txt | 11 +++ .../baselines/reference/unionTypeInference.js | 15 ++++ .../reference/unionTypeInference.symbols | 83 +++++++++++++++---- .../reference/unionTypeInference.types | 26 ++++++ 4 files changed, 118 insertions(+), 17 deletions(-) diff --git a/tests/baselines/reference/unionTypeInference.errors.txt b/tests/baselines/reference/unionTypeInference.errors.txt index 2fe480d0a07..f28f32f3373 100644 --- a/tests/baselines/reference/unionTypeInference.errors.txt +++ b/tests/baselines/reference/unionTypeInference.errors.txt @@ -39,6 +39,17 @@ tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference ~~ !!! error TS2345: Argument of type '42' is not assignable to parameter of type 'never'. + export interface Foo { + then(f: (x: T) => U | Foo, g: U): Foo; + } + export interface Bar { + then(f: (x: T) => S | Bar, g: S): Bar; + } + + function qux(p1: Foo, p2: Bar) { + p1 = p2; + } + // Repros from #32434 declare function foo(x: T | Promise): void; diff --git a/tests/baselines/reference/unionTypeInference.js b/tests/baselines/reference/unionTypeInference.js index 868140e83a0..e41872eb4d4 100644 --- a/tests/baselines/reference/unionTypeInference.js +++ b/tests/baselines/reference/unionTypeInference.js @@ -31,6 +31,17 @@ const d1 = f4("abc"); const d2 = f4(s); const d3 = f4(42); // Error +export interface Foo { + then(f: (x: T) => U | Foo, g: U): Foo; +} +export interface Bar { + then(f: (x: T) => S | Bar, g: S): Bar; +} + +function qux(p1: Foo, p2: Bar) { + p1 = p2; +} + // Repros from #32434 declare function foo(x: T | Promise): void; @@ -43,6 +54,7 @@ const y = bar(1, 2); //// [unionTypeInference.js] "use strict"; +exports.__esModule = true; var a1 = f1(1, 2); // 1 | 2 var a2 = f1(1, "hello"); // 1 var a3 = f1(1, sn); // number @@ -59,5 +71,8 @@ var c5 = f3("abc"); // never var d1 = f4("abc"); var d2 = f4(s); var d3 = f4(42); // Error +function qux(p1, p2) { + p1 = p2; +} foo(x); var y = bar(1, 2); diff --git a/tests/baselines/reference/unionTypeInference.symbols b/tests/baselines/reference/unionTypeInference.symbols index 52b8809dee6..0d0bf6ae9be 100644 --- a/tests/baselines/reference/unionTypeInference.symbols +++ b/tests/baselines/reference/unionTypeInference.symbols @@ -107,34 +107,83 @@ const d3 = f4(42); // Error >d3 : Symbol(d3, Decl(unionTypeInference.ts, 30, 5)) >f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21)) +export interface Foo { +>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18)) +>T : Symbol(T, Decl(unionTypeInference.ts, 32, 21)) + + then(f: (x: T) => U | Foo, g: U): Foo; +>then : Symbol(Foo.then, Decl(unionTypeInference.ts, 32, 25)) +>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9)) +>f : Symbol(f, Decl(unionTypeInference.ts, 33, 12)) +>x : Symbol(x, Decl(unionTypeInference.ts, 33, 16)) +>T : Symbol(T, Decl(unionTypeInference.ts, 32, 21)) +>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9)) +>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18)) +>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9)) +>g : Symbol(g, Decl(unionTypeInference.ts, 33, 36)) +>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9)) +>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18)) +>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9)) +} +export interface Bar { +>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1)) +>T : Symbol(T, Decl(unionTypeInference.ts, 35, 21)) + + then(f: (x: T) => S | Bar, g: S): Bar; +>then : Symbol(Bar.then, Decl(unionTypeInference.ts, 35, 25)) +>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9)) +>f : Symbol(f, Decl(unionTypeInference.ts, 36, 12)) +>x : Symbol(x, Decl(unionTypeInference.ts, 36, 16)) +>T : Symbol(T, Decl(unionTypeInference.ts, 35, 21)) +>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9)) +>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1)) +>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9)) +>g : Symbol(g, Decl(unionTypeInference.ts, 36, 36)) +>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9)) +>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1)) +>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9)) +} + +function qux(p1: Foo, p2: Bar) { +>qux : Symbol(qux, Decl(unionTypeInference.ts, 37, 1)) +>p1 : Symbol(p1, Decl(unionTypeInference.ts, 39, 13)) +>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18)) +>p2 : Symbol(p2, Decl(unionTypeInference.ts, 39, 27)) +>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1)) + + p1 = p2; +>p1 : Symbol(p1, Decl(unionTypeInference.ts, 39, 13)) +>p2 : Symbol(p2, Decl(unionTypeInference.ts, 39, 27)) +} + // Repros from #32434 declare function foo(x: T | Promise): void; ->foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 18)) ->T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) ->x : Symbol(x, Decl(unionTypeInference.ts, 34, 24)) ->T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) +>foo : Symbol(foo, Decl(unionTypeInference.ts, 41, 1)) +>T : Symbol(T, Decl(unionTypeInference.ts, 45, 21)) +>x : Symbol(x, Decl(unionTypeInference.ts, 45, 24)) +>T : Symbol(T, Decl(unionTypeInference.ts, 45, 21)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(unionTypeInference.ts, 34, 21)) +>T : Symbol(T, Decl(unionTypeInference.ts, 45, 21)) declare let x: false | Promise; ->x : Symbol(x, Decl(unionTypeInference.ts, 35, 11)) +>x : Symbol(x, Decl(unionTypeInference.ts, 46, 11)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) foo(x); ->foo : Symbol(foo, Decl(unionTypeInference.ts, 30, 18)) ->x : Symbol(x, Decl(unionTypeInference.ts, 35, 11)) +>foo : Symbol(foo, Decl(unionTypeInference.ts, 41, 1)) +>x : Symbol(x, Decl(unionTypeInference.ts, 46, 11)) declare function bar(x: T, y: string | T): T; ->bar : Symbol(bar, Decl(unionTypeInference.ts, 36, 7)) ->T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) ->x : Symbol(x, Decl(unionTypeInference.ts, 38, 24)) ->T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) ->y : Symbol(y, Decl(unionTypeInference.ts, 38, 29)) ->T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) ->T : Symbol(T, Decl(unionTypeInference.ts, 38, 21)) +>bar : Symbol(bar, Decl(unionTypeInference.ts, 47, 7)) +>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21)) +>x : Symbol(x, Decl(unionTypeInference.ts, 49, 24)) +>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21)) +>y : Symbol(y, Decl(unionTypeInference.ts, 49, 29)) +>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21)) +>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21)) const y = bar(1, 2); ->y : Symbol(y, Decl(unionTypeInference.ts, 39, 5)) ->bar : Symbol(bar, Decl(unionTypeInference.ts, 36, 7)) +>y : Symbol(y, Decl(unionTypeInference.ts, 50, 5)) +>bar : Symbol(bar, Decl(unionTypeInference.ts, 47, 7)) diff --git a/tests/baselines/reference/unionTypeInference.types b/tests/baselines/reference/unionTypeInference.types index e6d47fa4bda..6675e63f8c4 100644 --- a/tests/baselines/reference/unionTypeInference.types +++ b/tests/baselines/reference/unionTypeInference.types @@ -131,6 +131,32 @@ const d3 = f4(42); // Error >f4 : (x: string & T) => T >42 : 42 +export interface Foo { + then(f: (x: T) => U | Foo, g: U): Foo; +>then : (f: (x: T) => U | Foo, g: U) => Foo +>f : (x: T) => U | Foo +>x : T +>g : U +} +export interface Bar { + then(f: (x: T) => S | Bar, g: S): Bar; +>then : (f: (x: T) => S | Bar, g: S) => Bar +>f : (x: T) => S | Bar +>x : T +>g : S +} + +function qux(p1: Foo, p2: Bar) { +>qux : (p1: Foo, p2: Bar) => void +>p1 : Foo +>p2 : Bar + + p1 = p2; +>p1 = p2 : Bar +>p1 : Foo +>p2 : Bar +} + // Repros from #32434 declare function foo(x: T | Promise): void; From 2541a5d0fff2037854732253dfc74a096d4c1c04 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jul 2019 14:33:35 -0700 Subject: [PATCH 16/30] Always infer between distinct type references to same target --- src/compiler/checker.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0b4ae0d9d33..7b39ce98b93 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15958,9 +15958,14 @@ namespace ts { } } + function isTypeReferenceToSameTarget(source: Type, target: Type) { + return !!(getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && + (source).target === (target).target); + } + function typeIdenticalToSomeType(type: Type, types: Type[]): boolean { for (const t of types) { - if (isTypeIdenticalTo(t, type)) { + if (t === type || !isTypeReferenceToSameTarget(t, type) && isTypeIdenticalTo(t, type)) { return true; } } From 9b2d9cdffcc540d875b0cab533b9915337fa2097 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 21 Jul 2019 14:07:45 -0700 Subject: [PATCH 17/30] Fix issues uncovered by DT tests --- src/compiler/checker.ts | 50 +++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7b39ce98b93..19517b6715c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13540,6 +13540,9 @@ namespace ts { if (relation !== identityRelation) { source = getApparentType(source); } + else if (isGenericMappedType(source)) { + return Ternary.False; + } if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && !(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) { // We have type references to the same generic type, and the type references are not marker @@ -15456,7 +15459,7 @@ namespace ts { function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, contravariant = false) { let symbolStack: Symbol[]; - let visited: Map; + let visited: Map; let bivariant = false; let propagationType: Type; let inferenceCount = 0; @@ -15656,15 +15659,17 @@ namespace ts { } if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { const key = source.id + "," + target.id; - if (visited && visited.get(key)) { - inferenceBlocked = true; + const visitCount = visited && visited.get(key); + if (visitCount !== undefined) { + inferenceCount += visitCount; return; } - (visited || (visited = createMap())).set(key, true); + (visited || (visited = createMap())).set(key, 0); // If we are already processing another target type with the same associated symbol (such as // an instantiation of the same generic type), we do not explore this target as it would yield // no further inferences. We exclude the static side of classes from this check since it shares // its symbol with the instance side which would lead to false positives. + const startCount = inferenceCount; const isNonConstructorObject = target.flags & TypeFlags.Object && !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class); const symbol = isNonConstructorObject ? target.symbol : undefined; @@ -15680,14 +15685,21 @@ namespace ts { else { inferFromObjectTypes(source, target); } + visited.set(key, inferenceCount - startCount); } } function inferFromTypesOnce(source: Type, target: Type) { const key = source.id + "," + target.id; - if (!visited || !visited.get(key)) { - (visited || (visited = createMap())).set(key, true); + const count = visited && visited.get(key); + if (count !== undefined) { + inferenceCount += count; + } + else { + (visited || (visited = createMap())).set(key, 0); + const startCount = inferenceCount; inferFromTypes(source, target); + visited.set(key, inferenceCount - startCount); } } } @@ -15780,23 +15792,28 @@ namespace ts { // type variable. If there is more than one naked type variable, or if inference was blocked // (meaning we didn't explore the types fully), give lower priority to the inferences as // they are less specific. - if (typeVariableCount > 0) { + if (typeVariableCount === 1 && !inferenceBlocked) { const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); if (unmatched.length) { const s = getUnionType(unmatched); - const savePriority = priority; - if (typeVariableCount > 1 || inferenceBlocked) { - priority |= InferencePriority.NakedTypeVariable; - } for (const t of target.types) { if (getInferenceInfoForType(t)) { inferFromTypes(s, t); } } - priority = savePriority; } } - inferenceBlocked = saveInferenceBlocked; + inferenceBlocked = inferenceBlocked || saveInferenceBlocked; + if (typeVariableCount > 0) { + const savePriority = priority; + priority |= InferencePriority.NakedTypeVariable; + for (const t of target.types) { + if (getInferenceInfoForType(t)) { + inferFromTypes(source, t); + } + } + priority = savePriority; + } } function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { @@ -15958,14 +15975,13 @@ namespace ts { } } - function isTypeReferenceToSameTarget(source: Type, target: Type) { - return !!(getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && - (source).target === (target).target); + function isMatchableType(type: Type) { + return !(type.flags & TypeFlags.Object) || !!(getObjectFlags(type) & ObjectFlags.Anonymous); } function typeIdenticalToSomeType(type: Type, types: Type[]): boolean { for (const t of types) { - if (t === type || !isTypeReferenceToSameTarget(t, type) && isTypeIdenticalTo(t, type)) { + if (t === type || isMatchableType(t) && isMatchableType(type) && isTypeIdenticalTo(t, type)) { return true; } } From 203fd9ff9e1a9923a7dc663cc738c4072b6431ee Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 Jul 2019 08:01:22 -0700 Subject: [PATCH 18/30] Combine multiple separate code paths --- src/compiler/checker.ts | 195 ++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 108 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 19517b6715c..9f64e13911c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15577,7 +15577,7 @@ namespace ts { // Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine const simplified = getSimplifiedType(target, /*writing*/ false); if (simplified !== target) { - inferFromTypesOnce(source, simplified); + invokeOnce(source, simplified, inferFromTypes); } else if (target.flags & TypeFlags.IndexedAccess) { const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false); @@ -15586,7 +15586,7 @@ namespace ts { if (indexType.flags & TypeFlags.Instantiable) { const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false); if (simplified && simplified !== target) { - inferFromTypesOnce(source, simplified); + invokeOnce(source, simplified, inferFromTypes); } } } @@ -15621,15 +15621,12 @@ namespace ts { inferFromTypes(getTrueTypeFromConditionalType(source), getTrueTypeFromConditionalType(target)); inferFromTypes(getFalseTypeFromConditionalType(source), getFalseTypeFromConditionalType(target)); } - else if (target.flags & TypeFlags.Union) { - inferToUnionType(source, target); - } - else if (target.flags & TypeFlags.Intersection) { - inferToMultipleTypes(source, (target).types, /*isIntersection*/ true); - } else if (target.flags & TypeFlags.Conditional && !contravariant) { const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; - inferToMultipleTypes(source, targetTypes, /*isIntersection*/ false); + inferToMultipleTypes(source, targetTypes, target.flags); + } + else if (target.flags & TypeFlags.UnionOrIntersection) { + inferToMultipleTypes(source, (target).types, target.flags); } else if (source.flags & TypeFlags.Union) { // Source is a union or intersection type, infer from each constituent type @@ -15658,50 +15655,22 @@ namespace ts { source = apparentSource; } if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { - const key = source.id + "," + target.id; - const visitCount = visited && visited.get(key); - if (visitCount !== undefined) { - inferenceCount += visitCount; - return; - } - (visited || (visited = createMap())).set(key, 0); - // If we are already processing another target type with the same associated symbol (such as - // an instantiation of the same generic type), we do not explore this target as it would yield - // no further inferences. We exclude the static side of classes from this check since it shares - // its symbol with the instance side which would lead to false positives. - const startCount = inferenceCount; - const isNonConstructorObject = target.flags & TypeFlags.Object && - !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class); - const symbol = isNonConstructorObject ? target.symbol : undefined; - if (symbol) { - if (contains(symbolStack, symbol)) { - inferenceBlocked = true; - return; - } - (symbolStack || (symbolStack = [])).push(symbol); - inferFromObjectTypes(source, target); - symbolStack.pop(); - } - else { - inferFromObjectTypes(source, target); - } - visited.set(key, inferenceCount - startCount); + invokeOnce(source, target, inferFromObjectTypes); } } + } - function inferFromTypesOnce(source: Type, target: Type) { - const key = source.id + "," + target.id; - const count = visited && visited.get(key); - if (count !== undefined) { - inferenceCount += count; - } - else { - (visited || (visited = createMap())).set(key, 0); - const startCount = inferenceCount; - inferFromTypes(source, target); - visited.set(key, inferenceCount - startCount); - } + function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) { + const key = source.id + "," + target.id; + const count = visited && visited.get(key); + if (count !== undefined) { + inferenceCount += count; + return; } + (visited || (visited = createMap())).set(key, 0); + const startCount = inferenceCount; + action(source, target); + visited.set(key, inferenceCount - startCount); } function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) { @@ -15738,24 +15707,61 @@ namespace ts { return undefined; } - function inferToMultipleTypes(source: Type, targets: Type[], isIntersection: boolean) { - // We infer from types that are not naked type variables first so that inferences we - // make from nested naked type variables and given slightly higher priority by virtue - // of being first in the candidates array. + function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) { let typeVariableCount = 0; - for (const t of targets) { - if (getInferenceInfoForType(t)) { - typeVariableCount++; + if (targetFlags & TypeFlags.Union) { + const sources = source.flags & TypeFlags.Union ? (source).types : [source]; + const matched = new Array(sources.length); + const saveInferenceBlocked = inferenceBlocked; + inferenceBlocked = false; + // First infer to types that are not naked type variables. For each source type we + // track whether inferences were made from that particular type to some target. + for (const t of targets) { + if (getInferenceInfoForType(t)) { + typeVariableCount++; + } + else { + for (let i = 0; i < sources.length; i++) { + const count = inferenceCount; + inferFromTypes(sources[i], t); + if (count !== inferenceCount) matched[i] = true; + } + } } - else { - inferFromTypes(source, t); + // If the target has a single naked type variable and inference wasn't blocked (meaning + // we explored the types fully), create a union of the source types from which no inferences + // have been made so far and infer from that union to the naked type variable. + if (typeVariableCount === 1 && !inferenceBlocked) { + const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); + if (unmatched.length) { + const s = getUnionType(unmatched); + for (const t of targets) { + if (getInferenceInfoForType(t)) { + inferFromTypes(s, t); + } + } + } + } + inferenceBlocked = inferenceBlocked || saveInferenceBlocked; + } + else { + // We infer from types that are not naked type variables first so that inferences we + // make from nested naked type variables and given slightly higher priority by virtue + // of being first in the candidates array. + for (const t of targets) { + if (getInferenceInfoForType(t)) { + typeVariableCount++; + } + else { + inferFromTypes(source, t); + } } } // Inferences directly to naked type variables are given lower priority as they are // less specific. For example, when inferring from Promise to T | Promise, // we want to infer string for T, not Promise | string. For intersection types // we only infer to single naked type variables. - if (isIntersection ? typeVariableCount === 1 : typeVariableCount !== 0) { + if (targetFlags & TypeFlags.Intersection ? typeVariableCount === 1 : typeVariableCount > 0) { const savePriority = priority; priority |= InferencePriority.NakedTypeVariable; for (const t of targets) { @@ -15767,55 +15773,6 @@ namespace ts { } } - function inferToUnionType(source: Type, target: UnionType) { - const sources = source.flags & TypeFlags.Union ? (source).types : [source]; - const matched = new Array(sources.length); - let typeVariableCount = 0; - const saveInferenceBlocked = inferenceBlocked; - inferenceBlocked = false; - // First infer to types that are not naked type variables. For each source type we - // track whether inferences were made from that particular type to some target. - for (const t of target.types) { - if (getInferenceInfoForType(t)) { - typeVariableCount++; - } - else { - for (let i = 0; i < sources.length; i++) { - const count = inferenceCount; - inferFromTypes(sources[i], t); - if (count !== inferenceCount) matched[i] = true; - } - } - } - // If there are naked type variables in the target, create a union of the source types - // from which no inferences have been made so far and infer from that union to each naked - // type variable. If there is more than one naked type variable, or if inference was blocked - // (meaning we didn't explore the types fully), give lower priority to the inferences as - // they are less specific. - if (typeVariableCount === 1 && !inferenceBlocked) { - const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); - if (unmatched.length) { - const s = getUnionType(unmatched); - for (const t of target.types) { - if (getInferenceInfoForType(t)) { - inferFromTypes(s, t); - } - } - } - } - inferenceBlocked = inferenceBlocked || saveInferenceBlocked; - if (typeVariableCount > 0) { - const savePriority = priority; - priority |= InferencePriority.NakedTypeVariable; - for (const t of target.types) { - if (getInferenceInfoForType(t)) { - inferFromTypes(source, t); - } - } - priority = savePriority; - } - } - function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { if (constraintType.flags & TypeFlags.Union) { let result = false; @@ -15873,6 +15830,28 @@ namespace ts { } function inferFromObjectTypes(source: Type, target: Type) { + // If we are already processing another target type with the same associated symbol (such as + // an instantiation of the same generic type), we do not explore this target as it would yield + // no further inferences. We exclude the static side of classes from this check since it shares + // its symbol with the instance side which would lead to false positives. + const isNonConstructorObject = target.flags & TypeFlags.Object && + !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class); + const symbol = isNonConstructorObject ? target.symbol : undefined; + if (symbol) { + if (contains(symbolStack, symbol)) { + inferenceBlocked = true; + return; + } + (symbolStack || (symbolStack = [])).push(symbol); + inferFromObjectTypesWorker(source, target); + symbolStack.pop(); + } + else { + inferFromObjectTypesWorker(source, target); + } + } + + function inferFromObjectTypesWorker(source: Type, target: Type) { if (isGenericMappedType(source) && isGenericMappedType(target)) { // The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer // from S to T and from X to Y. From b822def6effe8521d14b218bf3287d83c761de21 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 Jul 2019 11:07:33 -0700 Subject: [PATCH 19/30] Minor cleanup plus more comments --- src/compiler/checker.ts | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9f64e13911c..0a64e0552e2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15463,7 +15463,7 @@ namespace ts { let bivariant = false; let propagationType: Type; let inferenceCount = 0; - let inferenceBlocked = false; + let inferenceIncomplete = false; let allowComplexConstraintInference = true; inferFromTypes(originalSource, originalTarget); @@ -15710,14 +15710,16 @@ namespace ts { function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) { let typeVariableCount = 0; if (targetFlags & TypeFlags.Union) { + let nakedTypeVariable: Type | undefined; const sources = source.flags & TypeFlags.Union ? (source).types : [source]; const matched = new Array(sources.length); - const saveInferenceBlocked = inferenceBlocked; - inferenceBlocked = false; + const saveInferenceIncomplete = inferenceIncomplete; + inferenceIncomplete = false; // First infer to types that are not naked type variables. For each source type we // track whether inferences were made from that particular type to some target. for (const t of targets) { if (getInferenceInfoForType(t)) { + nakedTypeVariable = t; typeVariableCount++; } else { @@ -15728,21 +15730,18 @@ namespace ts { } } } - // If the target has a single naked type variable and inference wasn't blocked (meaning - // we explored the types fully), create a union of the source types from which no inferences + const inferenceComplete = !inferenceIncomplete; + inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete; + // If the target has a single naked type variable and inference completed (meaning we + // explored the types fully), create a union of the source types from which no inferences // have been made so far and infer from that union to the naked type variable. - if (typeVariableCount === 1 && !inferenceBlocked) { + if (typeVariableCount === 1 && inferenceComplete) { const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); if (unmatched.length) { - const s = getUnionType(unmatched); - for (const t of targets) { - if (getInferenceInfoForType(t)) { - inferFromTypes(s, t); - } - } + inferFromTypes(getUnionType(unmatched), nakedTypeVariable!); + return; } } - inferenceBlocked = inferenceBlocked || saveInferenceBlocked; } else { // We infer from types that are not naked type variables first so that inferences we @@ -15839,7 +15838,7 @@ namespace ts { const symbol = isNonConstructorObject ? target.symbol : undefined; if (symbol) { if (contains(symbolStack, symbol)) { - inferenceBlocked = true; + inferenceIncomplete = true; return; } (symbolStack || (symbolStack = [])).push(symbol); @@ -15955,10 +15954,13 @@ namespace ts { } function isMatchableType(type: Type) { + // We exclude non-anonymous object types because some frameworks (e.g. Ember) rely on the ability to + // infer between types that don't witness their type variables. Such types would otherwise be eliminated + // because they appear identical. return !(type.flags & TypeFlags.Object) || !!(getObjectFlags(type) & ObjectFlags.Anonymous); } - function typeIdenticalToSomeType(type: Type, types: Type[]): boolean { + function typeMatchedBySomeType(type: Type, types: Type[]): boolean { for (const t of types) { if (t === type || isMatchableType(t) && isMatchableType(type) && isTypeIdenticalTo(t, type)) { return true; @@ -15968,12 +15970,12 @@ namespace ts { } function findMatchedType(type: Type, target: UnionOrIntersectionType) { - if (typeIdenticalToSomeType(type, target.types)) { + if (typeMatchedBySomeType(type, target.types)) { return type; } if (type.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral) && target.flags & TypeFlags.Union) { const base = getBaseTypeOfLiteralType(type); - if (typeIdenticalToSomeType(base, target.types)) { + if (typeMatchedBySomeType(base, target.types)) { return base; } } @@ -15987,7 +15989,7 @@ namespace ts { function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) { const reducedTypes: Type[] = []; for (const t of type.types) { - if (!typeIdenticalToSomeType(t, typesToRemove)) { + if (!typeMatchedBySomeType(t, typesToRemove)) { reducedTypes.push(t); } } From 3206f5fb94d7962c6f0588289a5c670bfc0b4b54 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 23 Jul 2019 06:38:49 -0700 Subject: [PATCH 20/30] When inferring from XXX to T | XXX make no inferece for T (instead of never) --- src/compiler/checker.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0a64e0552e2..72d91c184d7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15515,16 +15515,18 @@ namespace ts { // removing the identically matched constituents. For example, when inferring from // 'string | string[]' to 'string | T' we reduce the types to 'string[]' and 'T'. if (matchingTypes) { - source = removeTypesFromUnionOrIntersection(source, matchingTypes); - target = removeTypesFromUnionOrIntersection(target, matchingTypes); + const s = removeTypesFromUnionOrIntersection(source, matchingTypes); + const t = removeTypesFromUnionOrIntersection(target, matchingTypes); + if (!(s && t)) return; + source = s; + target = t; } } else if (target.flags & TypeFlags.Union && !(target.flags & TypeFlags.EnumLiteral) || target.flags & TypeFlags.Intersection) { const matched = findMatchedType(source, target); if (matched) { inferFromTypes(matched, matched); - source = target.flags & TypeFlags.Union ? neverType : unknownType; - target = removeTypesFromUnionOrIntersection(target, [matched]); + return; } } else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) { @@ -15993,7 +15995,7 @@ namespace ts { reducedTypes.push(t); } } - return type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes); + return reducedTypes.length ? type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes) : undefined; } function hasPrimitiveConstraint(type: TypeParameter): boolean { From 564685692f8103e6b8f90dd47283aa2363ef768f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 23 Jul 2019 06:38:58 -0700 Subject: [PATCH 21/30] Accept new baselines --- .../baselines/reference/unionAndIntersectionInference2.types | 2 +- tests/baselines/reference/unionTypeInference.types | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/unionAndIntersectionInference2.types b/tests/baselines/reference/unionAndIntersectionInference2.types index 031354506b7..24f24220bd9 100644 --- a/tests/baselines/reference/unionAndIntersectionInference2.types +++ b/tests/baselines/reference/unionAndIntersectionInference2.types @@ -20,7 +20,7 @@ var e1: number | string | boolean; >e1 : string | number | boolean f1(a1); // string ->f1(a1) : never +>f1(a1) : unknown >f1 : (x: string | T) => T >a1 : string diff --git a/tests/baselines/reference/unionTypeInference.types b/tests/baselines/reference/unionTypeInference.types index 6675e63f8c4..304bbcd33ec 100644 --- a/tests/baselines/reference/unionTypeInference.types +++ b/tests/baselines/reference/unionTypeInference.types @@ -104,8 +104,8 @@ const c4 = f3(b); // true >b : boolean const c5 = f3("abc"); // never ->c5 : never ->f3("abc") : never +>c5 : unknown +>f3("abc") : unknown >f3 : (x: string | false | T) => T >"abc" : "abc" From b8e779d89ad939d1740542e8f01347670b116cb0 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 23 Jul 2019 16:28:22 -0700 Subject: [PATCH 22/30] When the exported symbol is merged symbol from declaration use that name to verify quality Fixes #27880 --- src/services/codefixes/importFixes.ts | 7 ++- .../completionsImport_default_symbolName.ts | 44 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/completionsImport_default_symbolName.ts diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 8006d1a0cfd..5f1754c3036 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -445,9 +445,12 @@ namespace ts.codefix { const aliased = checker.getImmediateAliasedSymbol(defaultExport); return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions); } - else { - return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) }; + + if (defaultExport.escapedName !== InternalSymbolName.Default && + defaultExport.escapedName !== InternalSymbolName.ExportEquals) { + return { symbolForMeaning: defaultExport, name: defaultExport.getName() }; } + return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) }; } function getNameForExportDefault(symbol: Symbol): string | undefined { diff --git a/tests/cases/fourslash/completionsImport_default_symbolName.ts b/tests/cases/fourslash/completionsImport_default_symbolName.ts new file mode 100644 index 00000000000..0ede7a1673a --- /dev/null +++ b/tests/cases/fourslash/completionsImport_default_symbolName.ts @@ -0,0 +1,44 @@ +/// + +// @module: commonjs + +// @Filename: /node_modules/@types/range-parser/index.d.ts +////declare function RangeParser(): string; +////declare namespace RangeParser { +//// interface Options { +//// combine?: boolean; +//// } +////} +////export = RangeParser; + +// @Filename: /b.ts +////R/*0*/ + +verify.completions( + { + marker: "0", + includes: { + name: "RangeParser", + kind: "function", + kindModifiers: "declare", + source: "/node_modules/@types/range-parser/index", + sourceDisplay: "range-parser", + hasAction: true, + sortText: completion.SortText.AutoImportSuggestions, + text: `namespace RangeParser +function RangeParser(): string` + }, + preferences: { + includeCompletionsForModuleExports: true + } + }, +); + +verify.applyCodeActionFromCompletion("0", { + name: "RangeParser", + source: "/node_modules/@types/range-parser/index", + description: `Import 'RangeParser' from module "range-parser"`, + newFileContent: `import RangeParser = require("range-parser"); + +R`, +}); From 40fd4efdf6b61dcf1a2265c23d784a4974a5cfc7 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 23 Jul 2019 17:14:50 -0700 Subject: [PATCH 23/30] Strip more kinds of timestamps and versions from dockerfile output (#32519) * Strip more kinds of timestamps and versions from dockerfile output, rewrite office-ui-fabric dockerfile to use new lerna build system * Add another filter for just output * Update user baselines (#23) * Update user baselines (#24) * Strip only maybe-present timestamps * More lenient timestamp filter * Update user baselines (#25) * Simplify and enhance vscode dockerfile to use nightly ts in ts extension, too * Update user baselines (#26) * Update user baselines (#27) --- src/testRunner/externalCompileRunner.ts | 8 +- .../baselines/reference/docker/azure-sdk.log | 65 +- .../reference/docker/office-ui-fabric.log | 795 ++++++++++-------- tests/baselines/reference/docker/vscode.log | 31 +- .../cases/docker/office-ui-fabric/Dockerfile | 29 +- tests/cases/docker/vscode/Dockerfile | 10 +- tests/cases/user/prettier/prettier | 2 +- 7 files changed, 495 insertions(+), 445 deletions(-) diff --git a/src/testRunner/externalCompileRunner.ts b/src/testRunner/externalCompileRunner.ts index dbe7bc5854f..a47c0b59e24 100644 --- a/src/testRunner/externalCompileRunner.ts +++ b/src/testRunner/externalCompileRunner.ts @@ -185,7 +185,8 @@ function stripRushStageNumbers(result: string): string { * so we purge as much of the gulp output as we can */ function sanitizeUnimportantGulpOutput(result: string): string { - return result.replace(/^.*(\] (Starting)|(Finished)).*$/gm, "") // task start/end messages (nondeterministic order) + return result.replace(/^.*(\] (Starting)|(Finished)).*$/gm, "") // "gulp" task start/end messages (nondeterministic order) + .replace(/^.*(\] . (finished)|(started)).*$/gm, "") // "just" task start/end messages (nondeterministic order) .replace(/^.*\] Respawned to PID: \d+.*$/gm, "") // PID of child is OS and system-load dependent (likely stableish in a container but still dangerous) .replace(/\n+/g, "\n"); } @@ -193,14 +194,17 @@ function sanitizeUnimportantGulpOutput(result: string): string { function sanitizeTimestamps(result: string): string { return result.replace(/\[\d?\d:\d\d:\d\d (A|P)M\]/g, "[XX:XX:XX XM]") .replace(/\[\d?\d:\d\d:\d\d\]/g, "[XX:XX:XX]") + .replace(/\/\d+-\d+-[\d_TZ]+-debug.log/g, "\/XXXX-XX-XXXXXXXXX-debug.log") .replace(/\d+(\.\d+)? sec(onds?)?/g, "? seconds") .replace(/\d+(\.\d+)? min(utes?)?/g, "") - .replace(/\d+(\.\d+)?( m)?s/g, "?s"); + .replace(/\d+(\.\d+)? ?m?s/g, "?s") + .replace(/ \(\?s\)/g, ""); } function sanitizeVersionSpecifiers(result: string): string { return result .replace(/\d+.\d+.\d+-insiders.\d\d\d\d\d\d\d\d/g, "X.X.X-insiders.xxxxxxxx") + .replace(/Rush Multi-Project Build Tool (\d+)\.\d+\.\d+/g, "Rush Multi-Project Build Tool $1.X.X") .replace(/([@v\()])\d+\.\d+\.\d+/g, "$1X.X.X"); } diff --git a/tests/baselines/reference/docker/azure-sdk.log b/tests/baselines/reference/docker/azure-sdk.log index a75af93aee1..8728a9a8110 100644 --- a/tests/baselines/reference/docker/azure-sdk.log +++ b/tests/baselines/reference/docker/azure-sdk.log @@ -1,54 +1,41 @@ Exit Code: 1 Standard output: -Rush Multi-Project Build Tool 5.10.1 - https://rushjs.io +Rush Multi-Project Build Tool 5.X.X - https://rushjs.io Starting "rush rebuild" -Executing a maximum of 1 simultaneous processes... -[@azure/cosmos] started -XX of XX: [@azure/cosmos] completed successfully in ? seconds -[@azure/event-processor-host] started -XX of XX: [@azure/event-processor-host] completed successfully in ? seconds -[@azure/service-bus] started -Warning: You have changed the public API signature for this project. Updating review/service-bus.api.md -[@azure/storage-blob] started -XX of XX: [@azure/storage-blob] completed successfully in ? seconds -[@azure/storage-file] started -XX of XX: [@azure/storage-file] completed successfully in ? seconds -[@azure/storage-queue] started -XX of XX: [@azure/storage-queue] completed successfully in ? seconds -[@azure/template] started -XX of XX: [@azure/template] completed successfully in ? seconds -[testhub] started -XX of XX: [testhub] completed successfully in ? seconds -[@azure/abort-controller] started +Executing a maximum of ?simultaneous processes... XX of XX: [@azure/abort-controller] completed successfully in ? seconds -[@azure/core-asynciterator-polyfill] started XX of XX: [@azure/core-asynciterator-polyfill] completed successfully in ? seconds -[@azure/core-auth] started +XX of XX: [@azure/core-paging] completed successfully in ? seconds +XX of XX: [@azure/cosmos] completed successfully in ? seconds +XX of XX: [@azure/event-processor-host] completed successfully in ? seconds +Warning: You have changed the public API signature for this project. Updating review/service-bus.api.md +XX of XX: [@azure/storage-blob] completed successfully in ? seconds +XX of XX: [@azure/storage-file] completed successfully in ? seconds +XX of XX: [@azure/storage-queue] completed successfully in ? seconds +XX of XX: [@azure/template] completed successfully in ? seconds +XX of XX: [testhub] completed successfully in ? seconds XX of XX: [@azure/core-auth] completed successfully in ? seconds -[@azure/core-http] started npm ERR! code ELIFECYCLE npm ERR! errno 2 -npm ERR! @azure/core-http@X.X.X-preview.1 build:tsc: `tsc -p tsconfig.es.json` +npm ERR! @azure/core-http@X.X.X-preview.2 build:tsc: `tsc -p tsconfig.es.json` npm ERR! Exit status 2 npm ERR! -npm ERR! Failed at the @azure/core-http@X.X.X-preview.1 build:tsc script. +npm ERR! Failed at the @azure/core-http@X.X.X-preview.2 build:tsc script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: -npm ERR! /root/.npm/_logs/2019-07-19T13_40_31_496Z-debug.log +npm ERR! /root/.npm/_logs/XXXX-XX-XXXXXXXXX-debug.log ERROR: "build:tsc" exited with 2. npm ERR! code ELIFECYCLE npm ERR! errno 1 -npm ERR! @azure/core-http@X.X.X-preview.1 build:lib: `run-s build:tsc build:rollup build:minify-browser` +npm ERR! @azure/core-http@X.X.X-preview.2 build:lib: `run-s build:tsc build:rollup build:minify-browser` npm ERR! Exit status 1 npm ERR! -npm ERR! Failed at the @azure/core-http@X.X.X-preview.1 build:lib script. +npm ERR! Failed at the @azure/core-http@X.X.X-preview.2 build:lib script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: -npm ERR! /root/.npm/_logs/2019-07-19T13_40_31_533Z-debug.log +npm ERR! /root/.npm/_logs/XXXX-XX-XXXXXXXXX-debug.log ERROR: "build:lib" exited with 1. -[@azure/core-paging] started -XX of XX: [@azure/core-paging] completed successfully in ? seconds SUCCESS (11) ================================ @azure/abort-controller (? seconds) @@ -83,23 +70,23 @@ FAILURE (1) @azure/core-http (? seconds) npm ERR! code ELIFECYCLE npm ERR! errno 2 -npm ERR! @azure/core-http@X.X.X-preview.1 build:tsc: `tsc -p tsconfig.es.json` +npm ERR! @azure/core-http@X.X.X-preview.2 build:tsc: `tsc -p tsconfig.es.json` npm ERR! Exit status 2 npm ERR! -npm ERR! Failed at the @azure/core-http@X.X.X-preview.1 build:tsc script. +npm ERR! Failed at the @azure/core-http@X.X.X-preview.2 build:tsc script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: -npm ERR! /root/.npm/_logs/2019-07-19T13_40_31_496Z-debug.log +npm ERR! /root/.npm/_logs/XXXX-XX-XXXXXXXXX-debug.log ERROR: "build:tsc" exited with 2. npm ERR! code ELIFECYCLE npm ERR! errno 1 -npm ERR! @azure/core-http@X.X.X-preview.1 build:lib: `run-s build:tsc build:rollup build:minify-browser` +npm ERR! @azure/core-http@X.X.X-preview.2 build:lib: `run-s build:tsc build:rollup build:minify-browser` npm ERR! Exit status 1 npm ERR! -npm ERR! Failed at the @azure/core-http@X.X.X-preview.1 build:lib script. +npm ERR! Failed at the @azure/core-http@X.X.X-preview.2 build:lib script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: -npm ERR! /root/.npm/_logs/2019-07-19T13_40_31_533Z-debug.log +npm ERR! /root/.npm/_logs/XXXX-XX-XXXXXXXXX-debug.log ERROR: "build:lib" exited with 1. ================================ Error: Project(s) failed to build @@ -112,10 +99,10 @@ Your version of Node.js (X.X.X) has not been tested with this release of Rush. T XX of XX: [@azure/service-bus] completed with warnings in ? seconds XX of XX: [@azure/core-http] failed to build! XX of XX: [@azure/core-arm] blocked by [@azure/core-http]! -XX of XX: [@azure/identity] blocked by [@azure/core-http]! -XX of XX: [@azure/core-amqp] blocked by [@azure/core-http]! -XX of XX: [@azure/event-hubs] blocked by [@azure/core-http]! XX of XX: [@azure/keyvault-certificates] blocked by [@azure/core-http]! XX of XX: [@azure/keyvault-keys] blocked by [@azure/core-http]! XX of XX: [@azure/keyvault-secrets] blocked by [@azure/core-http]! +XX of XX: [@azure/identity] blocked by [@azure/core-http]! +XX of XX: [@azure/core-amqp] blocked by [@azure/core-http]! +XX of XX: [@azure/event-hubs] blocked by [@azure/core-http]! [@azure/core-http] Returned error code: 1 diff --git a/tests/baselines/reference/docker/office-ui-fabric.log b/tests/baselines/reference/docker/office-ui-fabric.log index 888e20cac4b..745bdff4193 100644 --- a/tests/baselines/reference/docker/office-ui-fabric.log +++ b/tests/baselines/reference/docker/office-ui-fabric.log @@ -1,371 +1,436 @@ Exit Code: 1 Standard output: - -Rush Multi-Project Build Tool 5.6.0 - https://rushjs.io -Starting "rush rebuild" -Executing a maximum of 1 simultaneous processes... -[@uifabric/prettier-rules] started -XX of XX: [@uifabric/prettier-rules] completed successfully in ? seconds -[@uifabric/tslint-rules] started -XX of XX: [@uifabric/tslint-rules] completed successfully in ? seconds -[@uifabric/codepen-loader] started -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. - PASS src/__tests__/codepenTransform.test.ts - codepen transform - ✓ handles examples with function components (256ms) - ✓ handles examples with class components (38ms) - ✓ handles examples importing exampleData (125ms) - ✓ handles examples importing TestImages (33ms) - ✓ handles examples importing PeopleExampleData (270ms) -Test Suites: 1 passed, 1 total -Tests: 5 passed, 5 total -Snapshots: 4 passed, 4 total -Time: ?s -Ran all test suites. -[@uifabric/build] started -XX of XX: [@uifabric/build] completed successfully in ? seconds -[@uifabric/migration] started -XX of XX: [@uifabric/migration] completed successfully in ? seconds -[@uifabric/set-version] started -XX of XX: [@uifabric/set-version] completed successfully in ? seconds -[@uifabric/merge-styles] started -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -[@uifabric/jest-serializer-merge-styles] started -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -[@uifabric/test-utilities] started -XX of XX: [@uifabric/test-utilities] completed successfully in ? seconds -[@uifabric/utilities] started -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -[@uifabric/styling] started -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -[@uifabric/file-type-icons] started -XX of XX: [@uifabric/file-type-icons] completed successfully in ? seconds -[@uifabric/foundation] started -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. - ● createFactory › passes componentProps without userProps - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:205:73) - ● createFactory › passes userProp string as child - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:210:76) - ● createFactory › passes userProp integer as child - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:220:76) - ● createFactory › passes userProp string as defaultProp - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:225:92) - ● createFactory › passes userProp integer as defaultProp - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:235:92) - ● createFactory › merges userProps over componentProps - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:245:84) - ● createFactory › renders div and userProp integer as children - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:255:86) - ● createFactory › renders div and userProp string as children - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:266:86) - ● createFactory › renders userProp span function without component props - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:288:61) - ● createFactory › renders userProp span function with component props - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:301:61) - ● createFactory › renders userProp span component with component props - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:314:61) - ● createFactory › passes props and type arguments to userProp function - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at Object. (src/slots.test.tsx:334:43) - ● getSlots › creates slots and passes merged props to them - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at _renderSlot (src/slots.tsx:221:100) - at Object.slot [as testSlot1] (src/slots.tsx:142:16) - at Object. (src/slots.test.tsx:399:24) -[XX:XX:XX XM] x Error detected while running 'jest' -[XX:XX:XX XM] x ------------------------------------ -[XX:XX:XX XM] x Error: Command failed: /usr/local/bin/node /office-ui-fabric-react/common/temp/node_modules/jest/bin/jest.js --config /office-ui-fabric-react/packages/foundation/jest.config.js --passWithNoTests --colors - at ChildProcess. (/office-ui-fabric-react/common/temp/node_modules/.registry.npmjs.org/just-scripts-utils/0.8.2/node_modules/just-scripts-utils/lib/exec.js:70:31) - at ChildProcess.emit (events.js:203:13) - at ChildProcess.EventEmitter.emit (domain.js:494:23) - at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12) -[XX:XX:XX XM] x ------------------------------------ -[XX:XX:XX XM] x finished 'validate' in ?s with errors -[XX:XX:XX XM] x finished 'build' in ?s with errors -[XX:XX:XX XM] x Error previously detected. See above for error messages. -[@uifabric/icons] started -XX of XX: [@uifabric/icons] completed successfully in ? seconds -[@uifabric/webpack-utils] started -XX of XX: [@uifabric/webpack-utils] completed successfully in ? seconds -SUCCESS (9) -================================ -@uifabric/build (? seconds) -@uifabric/file-type-icons (? seconds) -@uifabric/icons (? seconds) -@uifabric/migration (? seconds) -@uifabric/prettier-rules (? seconds) -@uifabric/set-version (? seconds) -@uifabric/test-utilities (? seconds) -@uifabric/tslint-rules (? seconds) -@uifabric/webpack-utils (? seconds) -================================ -SUCCESS WITH WARNINGS (5) -================================ -@uifabric/codepen-loader (? seconds) -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. - PASS src/__tests__/codepenTransform.test.ts - codepen transform - ✓ handles examples with function components (256ms) - ✓ handles examples with class components (38ms) - ✓ handles examples importing exampleData (125ms) - ✓ handles examples importing TestImages (33ms) - ✓ handles examples importing PeopleExampleData (270ms) -Test Suites: 1 passed, 1 total -Tests: 5 passed, 5 total -Snapshots: 4 passed, 4 total -Time: ?s -Ran all test suites. -@uifabric/jest-serializer-merge-styles (? seconds) -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -@uifabric/merge-styles (? seconds) -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -@uifabric/styling (? seconds) -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -@uifabric/utilities (? seconds) -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -================================ -BLOCKED (27) -================================ -@uifabric/api-docs -@uifabric/azure-themes -@uifabric/charting -@uifabric/date-time -@uifabric/example-app-base -@uifabric/experiments -@uifabric/fabric-website -@uifabric/fabric-website-resources -@uifabric/fluent-theme -@uifabric/foundation-scenarios -@uifabric/lists -@uifabric/mdl2-theme -@uifabric/pr-deploy-site -@uifabric/react-cards -@uifabric/theme-samples -@uifabric/tsx-editor -@uifabric/variants -a11y-tests -dom-tests -office-ui-fabric-react -perf-test -server-rendered-app -ssr-tests -test-bundles -theming-designer -todo-app -vr-tests -================================ -FAILURE (1) -================================ -@uifabric/foundation (? seconds) -ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. - ● createFactory › passes componentProps without userProps - RangeError: Invalid array length - 189 | for (const props of allProps) { - 190 | classNames.push(props && props.className); - > 191 | assign(finalProps, ...(props as any)); - | ^ - 192 | } - 193 | -[...179 lines omitted...] - 193 | - 194 | finalProps.className = mergeStyles(defaultStyles, classNames); - at Object.__spreadArrays (../../common/temp/node_modules/.registry.npmjs.org/tslib/1.10.0/node_modules/tslib/tslib.js:182:22) - at _constructFinalProps (src/slots.tsx:191:11) - at result (src/slots.tsx:88:24) - at _renderSlot (src/slots.tsx:221:100) - at Object.slot [as testSlot1] (src/slots.tsx:142:16) - at Object. (src/slots.test.tsx:399:24) -[XX:XX:XX XM] x Error detected while running 'jest' -[XX:XX:XX XM] x ------------------------------------ -[XX:XX:XX XM] x Error: Command failed: /usr/local/bin/node /office-ui-fabric-react/common/temp/node_modules/jest/bin/jest.js --config /office-ui-fabric-react/packages/foundation/jest.config.js --passWithNoTests --colors - at ChildProcess. (/office-ui-fabric-react/common/temp/node_modules/.registry.npmjs.org/just-scripts-utils/0.8.2/node_modules/just-scripts-utils/lib/exec.js:70:31) - at ChildProcess.emit (events.js:203:13) - at ChildProcess.EventEmitter.emit (domain.js:494:23) - at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12) -[XX:XX:XX XM] x ------------------------------------ -[XX:XX:XX XM] x finished 'validate' in ?s with errors -[XX:XX:XX XM] x finished 'build' in ?s with errors -[XX:XX:XX XM] x Error previously detected. See above for error messages. -================================ -Error: Project(s) failed to build -rush rebuild - Errors! ( ? seconds) +@uifabric/codepen-loader: yarn run vX.X.X +@uifabric/codepen-loader: $ just-scripts build --production --lint +@uifabric/codepen-loader: [XX:XX:XX XM] ■ Removing [lib, temp, dist, coverage, lib-commonjs] +@uifabric/codepen-loader: [XX:XX:XX XM] ■ Copying [../office-ui-fabric-react/src/utilities/exampleData.ts, ../office-ui-fabric-react/src/components/ExtendedPicker/examples/PeopleExampleData.ts, ../office-ui-fabric-react/src/common/TestImages.ts] to 'lib' +@uifabric/codepen-loader: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/codepen-loader/tsconfig.json +@uifabric/codepen-loader: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --module commonjs --outDir "./lib" --project "/office-ui-fabric-react/packages/codepen-loader/tsconfig.json" +@uifabric/codepen-loader: [XX:XX:XX XM] ■ Running Jest +@uifabric/codepen-loader: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/jest/bin/jest.js" --config "/office-ui-fabric-react/packages/codepen-loader/jest.config.js" --passWithNoTests --colors +@uifabric/codepen-loader: PASS src/__tests__/codepenTransform.test.ts +@uifabric/codepen-loader: Done in ?s. +@uifabric/build: yarn run vX.X.X +@uifabric/build: $ node ./just-scripts.js no-op --production --lint +@uifabric/build: Done in ?s. +@uifabric/migration: yarn run vX.X.X +@uifabric/migration: $ just-scripts build --production --lint +@uifabric/migration: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/migration: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/migration/tsconfig.json +@uifabric/migration: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module commonjs --project "/office-ui-fabric-react/packages/migration/tsconfig.json" +@uifabric/migration: Done in ?s. +@uifabric/set-version: yarn run vX.X.X +@uifabric/set-version: $ just-scripts build --production --lint +@uifabric/set-version: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/set-version: [XX:XX:XX XM] ■ Running tslint +@uifabric/set-version: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/tslint/lib/tslintCli.js" --project "/office-ui-fabric-react/packages/set-version/tsconfig.json" -t stylish -r /office-ui-fabric-react/node_modules/tslint-microsoft-contrib +@uifabric/set-version: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/set-version/tsconfig.json +@uifabric/set-version: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/set-version/tsconfig.json" +@uifabric/set-version: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/set-version/tsconfig.json +@uifabric/set-version: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/set-version/tsconfig.json" +@uifabric/set-version: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/set-version/tsconfig.json +@uifabric/set-version: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/set-version/tsconfig.json" +@uifabric/set-version: [XX:XX:XX XM] ■ Running Webpack +@uifabric/set-version: [XX:XX:XX XM] ■ Webpack Config Path: null +@uifabric/set-version: [XX:XX:XX XM] ■ webpack.config.js not found, skipping webpack +@uifabric/set-version: Done in ?s. +@uifabric/webpack-utils: yarn run vX.X.X +@uifabric/webpack-utils: $ just-scripts build --production --lint +@uifabric/webpack-utils: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/webpack-utils: [XX:XX:XX XM] ■ Running tslint +@uifabric/webpack-utils: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/tslint/lib/tslintCli.js" --project "/office-ui-fabric-react/packages/webpack-utils/tsconfig.json" -t stylish -r /office-ui-fabric-react/node_modules/tslint-microsoft-contrib +@uifabric/webpack-utils: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/webpack-utils/tsconfig.json +@uifabric/webpack-utils: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module commonjs --project "/office-ui-fabric-react/packages/webpack-utils/tsconfig.json" +@uifabric/webpack-utils: Done in ?s. +@uifabric/merge-styles: yarn run vX.X.X +@uifabric/merge-styles: $ just-scripts build --production --lint +@uifabric/merge-styles: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/merge-styles: [XX:XX:XX XM] ■ Running tslint +@uifabric/merge-styles: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/tslint/lib/tslintCli.js" --project "/office-ui-fabric-react/packages/merge-styles/tsconfig.json" -t stylish -r /office-ui-fabric-react/node_modules/tslint-microsoft-contrib +@uifabric/merge-styles: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/merge-styles/tsconfig.json +@uifabric/merge-styles: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/merge-styles/tsconfig.json" +@uifabric/merge-styles: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/merge-styles/tsconfig.json +@uifabric/merge-styles: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/merge-styles/tsconfig.json" +@uifabric/merge-styles: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/merge-styles/tsconfig.json +@uifabric/merge-styles: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/merge-styles/tsconfig.json" +@uifabric/merge-styles: [XX:XX:XX XM] ■ Running Jest +@uifabric/merge-styles: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/jest/bin/jest.js" --config "/office-ui-fabric-react/packages/merge-styles/jest.config.js" --passWithNoTests --colors +@uifabric/merge-styles: [XX:XX:XX XM] ■ Running Webpack +@uifabric/merge-styles: [XX:XX:XX XM] ■ Webpack Config Path: /office-ui-fabric-react/packages/merge-styles/webpack.config.js +@uifabric/merge-styles: Webpack version: 4.29.5 +@uifabric/merge-styles: PASS src/styleToClassName.test.ts +@uifabric/merge-styles: PASS src/mergeStyleSets.test.ts +@uifabric/merge-styles: PASS src/concatStyleSets.test.ts +@uifabric/merge-styles: PASS src/mergeStyles.test.ts +@uifabric/merge-styles: PASS src/transforms/rtlifyRules.test.ts +@uifabric/merge-styles: PASS src/transforms/prefixRules.test.ts +@uifabric/merge-styles: PASS src/transforms/provideUnits.test.ts +@uifabric/merge-styles: PASS src/keyframes.test.ts +@uifabric/merge-styles: PASS src/Stylesheet.test.ts +@uifabric/merge-styles: PASS src/extractStyleParts.test.ts +@uifabric/merge-styles: PASS src/server.test.ts +@uifabric/merge-styles: PASS src/fontFace.test.ts +@uifabric/merge-styles: PASS src/transforms/kebabRules.test.ts +@uifabric/merge-styles: [XX:XX:XX XM] ■ Extracting Public API surface from '/office-ui-fabric-react/packages/merge-styles/lib/index.d.ts' +@uifabric/merge-styles: Done in ?s. +@uifabric/jest-serializer-merge-styles: yarn run vX.X.X +@uifabric/jest-serializer-merge-styles: $ just-scripts build --production --lint +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/jest-serializer-merge-styles/tsconfig.json +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/jest-serializer-merge-styles/tsconfig.json" +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/jest-serializer-merge-styles/tsconfig.json +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/jest-serializer-merge-styles/tsconfig.json" +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/jest-serializer-merge-styles/tsconfig.json +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/jest-serializer-merge-styles/tsconfig.json" +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ Running Jest +@uifabric/jest-serializer-merge-styles: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/jest/bin/jest.js" --config "/office-ui-fabric-react/packages/jest-serializer-merge-styles/jest.config.js" --passWithNoTests --colors +@uifabric/jest-serializer-merge-styles: PASS src/index.test.tsx +@uifabric/jest-serializer-merge-styles: Done in ?s. +@uifabric/test-utilities: yarn run vX.X.X +@uifabric/test-utilities: $ just-scripts build --production --lint +@uifabric/test-utilities: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/test-utilities: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/test-utilities/tsconfig.json +@uifabric/test-utilities: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/test-utilities/tsconfig.json" +@uifabric/test-utilities: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/test-utilities/tsconfig.json +@uifabric/test-utilities: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/test-utilities/tsconfig.json" +@uifabric/test-utilities: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/test-utilities/tsconfig.json +@uifabric/test-utilities: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/test-utilities/tsconfig.json" +@uifabric/test-utilities: Done in ?s. +@uifabric/utilities: yarn run vX.X.X +@uifabric/utilities: $ just-scripts build --production --lint +@uifabric/utilities: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/utilities: [XX:XX:XX XM] ■ Running tslint +@uifabric/utilities: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/tslint/lib/tslintCli.js" --project "/office-ui-fabric-react/packages/utilities/tsconfig.json" -t stylish -r /office-ui-fabric-react/node_modules/tslint-microsoft-contrib +@uifabric/utilities: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/utilities/tsconfig.json +@uifabric/utilities: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/utilities/tsconfig.json" +@uifabric/utilities: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/utilities/tsconfig.json +@uifabric/utilities: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/utilities/tsconfig.json" +@uifabric/utilities: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/utilities/tsconfig.json +@uifabric/utilities: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/utilities/tsconfig.json" +@uifabric/utilities: [XX:XX:XX XM] ■ Running Jest +@uifabric/utilities: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/jest/bin/jest.js" --config "/office-ui-fabric-react/packages/utilities/jest.config.js" --passWithNoTests --colors +@uifabric/utilities: [XX:XX:XX XM] ■ Running Webpack +@uifabric/utilities: [XX:XX:XX XM] ■ Webpack Config Path: null +@uifabric/utilities: [XX:XX:XX XM] ■ webpack.config.js not found, skipping webpack +@uifabric/utilities: PASS src/warn/warnControlledUsage.test.ts +@uifabric/utilities: PASS src/focus.test.tsx +@uifabric/utilities: PASS src/styled.test.tsx +@uifabric/utilities: PASS src/EventGroup.test.ts +@uifabric/utilities: PASS src/array.test.ts +@uifabric/utilities: PASS src/customizations/Customizer.test.tsx +@uifabric/utilities: PASS src/math.test.ts +@uifabric/utilities: PASS src/warn/warn.test.ts +@uifabric/utilities: PASS src/dom/dom.test.ts +@uifabric/utilities: PASS src/customizations/customizable.test.tsx +@uifabric/utilities: PASS src/initials.test.ts +@uifabric/utilities: PASS src/selection/Selection.test.ts +@uifabric/utilities: PASS src/initializeFocusRects.test.ts +@uifabric/utilities: PASS src/memoize.test.ts +@uifabric/utilities: PASS src/osDetector.test.ts +@uifabric/utilities: PASS src/mobileDetector.test.ts +@uifabric/utilities: PASS src/aria.test.ts +@uifabric/utilities: PASS src/rtl.test.ts +@uifabric/utilities: PASS src/setFocusVisibility.test.ts +@uifabric/utilities: PASS src/properties.test.ts +@uifabric/utilities: PASS src/asAsync.test.tsx +@uifabric/utilities: PASS src/object.test.ts +@uifabric/utilities: PASS src/classNamesFunction.test.ts +@uifabric/utilities: PASS src/merge.test.ts +@uifabric/utilities: PASS src/customizations/Customizations.test.ts +@uifabric/utilities: PASS src/safeSetTimeout.test.tsx +@uifabric/utilities: PASS src/safeRequestAnimationFrame.test.tsx +@uifabric/utilities: PASS src/overflow.test.ts +@uifabric/utilities: PASS src/appendFunction.test.ts +@uifabric/utilities: PASS src/controlled.test.ts +@uifabric/utilities: PASS src/extendComponent.test.tsx +@uifabric/utilities: PASS src/initializeComponentRef.test.tsx +@uifabric/utilities: PASS src/BaseComponent.test.tsx +@uifabric/utilities: PASS src/keyboard.test.ts +@uifabric/utilities: PASS src/css.test.ts +@uifabric/utilities: [XX:XX:XX XM] ■ Extracting Public API surface from '/office-ui-fabric-react/packages/utilities/lib/index.d.ts' +@uifabric/utilities: Done in ?s. +@uifabric/styling: yarn run vX.X.X +@uifabric/styling: $ just-scripts build --production --lint +@uifabric/styling: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/styling: [XX:XX:XX XM] ■ Running tslint +@uifabric/styling: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/tslint/lib/tslintCli.js" --project "/office-ui-fabric-react/packages/styling/tsconfig.json" -t stylish -r /office-ui-fabric-react/node_modules/tslint-microsoft-contrib +@uifabric/styling: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/styling/tsconfig.json +@uifabric/styling: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/styling/tsconfig.json" +@uifabric/styling: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/styling/tsconfig.json +@uifabric/styling: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/styling/tsconfig.json" +@uifabric/styling: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/styling/tsconfig.json +@uifabric/styling: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/styling/tsconfig.json" +@uifabric/styling: [XX:XX:XX XM] ■ Running Jest +@uifabric/styling: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/jest/bin/jest.js" --config "/office-ui-fabric-react/packages/styling/jest.config.js" --passWithNoTests --colors +@uifabric/styling: [XX:XX:XX XM] ■ Running Webpack +@uifabric/styling: [XX:XX:XX XM] ■ Webpack Config Path: null +@uifabric/styling: [XX:XX:XX XM] ■ webpack.config.js not found, skipping webpack +@uifabric/styling: PASS src/styles/theme.test.ts +@uifabric/styling: PASS src/styles/scheme.test.ts +@uifabric/styling: PASS src/styles/getGlobalClassNames.test.ts +@uifabric/styling: PASS src/utilities/icons.test.ts +@uifabric/styling: PASS src/styles/fonts.test.ts +@uifabric/styling: [XX:XX:XX XM] ■ Extracting Public API surface from '/office-ui-fabric-react/packages/styling/lib/index.d.ts' +@uifabric/styling: Done in ?s. +@uifabric/file-type-icons: yarn run vX.X.X +@uifabric/file-type-icons: $ just-scripts build --production --lint +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Running tslint +@uifabric/file-type-icons: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/tslint/lib/tslintCli.js" --project "/office-ui-fabric-react/packages/file-type-icons/tsconfig.json" -t stylish -r /office-ui-fabric-react/node_modules/tslint-microsoft-contrib +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/file-type-icons/tsconfig.json +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/file-type-icons/tsconfig.json" +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/file-type-icons/tsconfig.json +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/file-type-icons/tsconfig.json" +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/file-type-icons/tsconfig.json +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/file-type-icons/tsconfig.json" +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Running Webpack +@uifabric/file-type-icons: [XX:XX:XX XM] ■ Webpack Config Path: null +@uifabric/file-type-icons: [XX:XX:XX XM] ■ webpack.config.js not found, skipping webpack +@uifabric/file-type-icons: Done in ?s. +@uifabric/foundation: yarn run vX.X.X +@uifabric/foundation: $ just-scripts build --production --lint +@uifabric/foundation: [XX:XX:XX XM] ■ Removing [lib, temp, dist, lib-amd, lib-commonjs, lib-es2015, coverage, src/**/*.scss.ts] +@uifabric/foundation: [XX:XX:XX XM] ■ Running tslint +@uifabric/foundation: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/tslint/lib/tslintCli.js" --project "/office-ui-fabric-react/packages/foundation/tsconfig.json" -t stylish -r /office-ui-fabric-react/node_modules/tslint-microsoft-contrib +@uifabric/foundation: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/foundation/tsconfig.json +@uifabric/foundation: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/foundation/tsconfig.json" +@uifabric/foundation: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/foundation/tsconfig.json +@uifabric/foundation: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module es2015 --project "/office-ui-fabric-react/packages/foundation/tsconfig.json" +@uifabric/foundation: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/foundation/tsconfig.json +@uifabric/foundation: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-amd --module amd --project "/office-ui-fabric-react/packages/foundation/tsconfig.json" +@uifabric/foundation: [XX:XX:XX XM] ■ Running Jest +@uifabric/foundation: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/jest/bin/jest.js" --config "/office-ui-fabric-react/packages/foundation/jest.config.js" --passWithNoTests --colors +@uifabric/foundation: [XX:XX:XX XM] ■ Running Webpack +@uifabric/foundation: [XX:XX:XX XM] ■ Webpack Config Path: /office-ui-fabric-react/packages/foundation/webpack.config.js +@uifabric/foundation: Webpack version: 4.29.5 +@uifabric/foundation: FAIL src/slots.test.tsx +@uifabric/foundation: PASS src/hooks/controlled.test.tsx +@uifabric/foundation: info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. Standard error: -Your version of Node.js (X.X.X) has not been tested with this release of Rush. The Rush team will not accept issue reports for it. Please consider upgrading Rush or downgrading Node.js. -XX of XX: [@uifabric/codepen-loader] completed with warnings in ? seconds -XX of XX: [@uifabric/merge-styles] completed with warnings in ? seconds -XX of XX: [@uifabric/jest-serializer-merge-styles] completed with warnings in ? seconds -XX of XX: [@uifabric/utilities] completed with warnings in ? seconds -XX of XX: [@uifabric/styling] completed with warnings in ? seconds -XX of XX: [@uifabric/foundation] failed to build! -XX of XX: [@uifabric/experiments] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/fabric-website] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/pr-deploy-site] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/react-cards] blocked by [@uifabric/foundation]! -XX of XX: [theming-designer] blocked by [@uifabric/foundation]! -XX of XX: [vr-tests] blocked by [@uifabric/foundation]! -XX of XX: [dom-tests] blocked by [@uifabric/foundation]! -XX of XX: [perf-test] blocked by [@uifabric/foundation]! -XX of XX: [test-bundles] blocked by [@uifabric/foundation]! -XX of XX: [office-ui-fabric-react] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/api-docs] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/fabric-website-resources] blocked by [@uifabric/foundation]! -XX of XX: [a11y-tests] blocked by [@uifabric/foundation]! -XX of XX: [ssr-tests] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/azure-themes] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/charting] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/date-time] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/example-app-base] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/foundation-scenarios] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/lists] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/fluent-theme] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/tsx-editor] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/mdl2-theme] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/theme-samples] blocked by [@uifabric/foundation]! -XX of XX: [@uifabric/variants] blocked by [@uifabric/foundation]! -XX of XX: [server-rendered-app] blocked by [@uifabric/foundation]! -XX of XX: [todo-app] blocked by [@uifabric/foundation]! -[@uifabric/foundation] Returned error code: 1 +info cli using local version of lerna +lerna notice cli vX.X.X +lerna info Executing command in 40 packages: "yarn run build --production --lint" +@uifabric/codepen-loader: ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. +@uifabric/set-version: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect +@uifabric/merge-styles: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect +@uifabric/merge-styles: ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. +@uifabric/jest-serializer-merge-styles: ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. +@uifabric/utilities: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect +@uifabric/utilities: ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. +@uifabric/styling: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect +@uifabric/styling: ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. +@uifabric/file-type-icons: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect +@uifabric/foundation: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect +@uifabric/foundation: ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. +@uifabric/foundation: ● createFactory › passes componentProps without userProps +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:205:73) +@uifabric/foundation: ● createFactory › passes userProp string as child +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:210:76) +@uifabric/foundation: ● createFactory › passes userProp integer as child +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:220:76) +@uifabric/foundation: ● createFactory › passes userProp string as defaultProp +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:225:92) +@uifabric/foundation: ● createFactory › passes userProp integer as defaultProp +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:235:92) +@uifabric/foundation: ● createFactory › merges userProps over componentProps +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:245:84) +@uifabric/foundation: ● createFactory › renders div and userProp integer as children +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:255:86) +@uifabric/foundation: ● createFactory › renders div and userProp string as children +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:266:86) +@uifabric/foundation: ● createFactory › renders userProp span function without component props +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:288:61) +@uifabric/foundation: ● createFactory › renders userProp span function with component props +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:301:61) +@uifabric/foundation: ● createFactory › renders userProp span component with component props +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:314:61) +@uifabric/foundation: ● createFactory › passes props and type arguments to userProp function +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at Object. (src/slots.test.tsx:334:43) +@uifabric/foundation: ● getSlots › creates slots and passes merged props to them +@uifabric/foundation: RangeError: Invalid array length +@uifabric/foundation: +@uifabric/foundation: 189 | for (const props of allProps) { +@uifabric/foundation: 190 | classNames.push(props && props.className); +@uifabric/foundation: > 191 | assign(finalProps, ...(props as any)); +@uifabric/foundation: | ^ +@uifabric/foundation: 192 | } +@uifabric/foundation: 193 | +@uifabric/foundation: 194 | finalProps.className = mergeStyles(defaultStyles, classNames); +@uifabric/foundation: +@uifabric/foundation: at Object.__spreadArrays (../../node_modules/tslib/tslib.js:182:22) +@uifabric/foundation: at _constructFinalProps (src/slots.tsx:191:11) +@uifabric/foundation: at result (src/slots.tsx:88:24) +@uifabric/foundation: at _renderSlot (src/slots.tsx:221:100) +@uifabric/foundation: at Object.slot [as testSlot1] (src/slots.tsx:142:16) +@uifabric/foundation: at Object. (src/slots.test.tsx:399:24) +@uifabric/foundation: [XX:XX:XX XM] x Error detected while running 'jest' +@uifabric/foundation: [XX:XX:XX XM] x ------------------------------------ +@uifabric/foundation: [XX:XX:XX XM] x Error: Command failed: /usr/local/bin/node /office-ui-fabric-react/node_modules/jest/bin/jest.js --config /office-ui-fabric-react/packages/foundation/jest.config.js --passWithNoTests --colors +@uifabric/foundation: at ChildProcess. (/office-ui-fabric-react/node_modules/just-scripts-utils/lib/exec.js:70:31) +@uifabric/foundation: at ChildProcess.emit (events.js:203:13) +@uifabric/foundation: at ChildProcess.EventEmitter.emit (domain.js:494:23) +@uifabric/foundation: at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12) +@uifabric/foundation: [XX:XX:XX XM] x ------------------------------------ +@uifabric/foundation: [XX:XX:XX XM] x Error previously detected. See above for error messages. +@uifabric/foundation: [XX:XX:XX XM] x Other tasks that did not complete: [webpack] +@uifabric/foundation: error Command failed with exit code 1. +lerna ERR! yarn run build --production --lint exited 1 in '@uifabric/foundation' +lerna WARN complete Waiting for 1 child process to exit. CTRL-C to exit immediately. diff --git a/tests/baselines/reference/docker/vscode.log b/tests/baselines/reference/docker/vscode.log index 8f23cb6719d..4775203f50e 100644 --- a/tests/baselines/reference/docker/vscode.log +++ b/tests/baselines/reference/docker/vscode.log @@ -4,31 +4,24 @@ yarn run vX.X.X $ gulp compile --max_old_space_size=4095 [XX:XX:XX] Node flags detected: --max_old_space_size=4095 [XX:XX:XX] Using gulpfile /vscode/gulpfile.js -[XX:XX:XX] Error: /vscode/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts(560,5): Type 'null' is not assignable to type 'string'. -[XX:XX:XX] Error: /vscode/src/vs/base/browser/ui/menu/menubar.ts(742,7): Type '"underline" | null' is not assignable to type 'string'. - Type 'null' is not assignable to type 'string'. -[XX:XX:XX] Error: /vscode/src/vs/editor/browser/controller/textAreaInput.ts(208,33): Property 'locale' does not exist on type 'CompositionEvent'. -[XX:XX:XX] Error: /vscode/src/vs/editor/browser/controller/textAreaInput.ts(225,33): Property 'locale' does not exist on type 'CompositionEvent'. -[XX:XX:XX] Error: /vscode/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts(560,5): Type 'null' is not assignable to type 'string'. -[XX:XX:XX] Error: /vscode/src/vs/base/browser/ui/menu/menubar.ts(742,7): Type '"underline" | null' is not assignable to type 'string'. - Type 'null' is not assignable to type 'string'. -[XX:XX:XX] Error: /vscode/src/vs/editor/browser/controller/textAreaInput.ts(208,33): Property 'locale' does not exist on type 'CompositionEvent'. -[XX:XX:XX] Error: /vscode/src/vs/editor/browser/controller/textAreaInput.ts(225,33): Property 'locale' does not exist on type 'CompositionEvent'. +[XX:XX:XX] Error: /vscode/node_modules/@types/node/index.d.ts(179,11): Duplicate identifier 'IteratorResult'. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. Standard error: -[XX:XX:XX] 'compile' errored after -[XX:XX:XX] Error: Found 4 errors +{"type":"warning","data":"package.json: No license field"} +{"type":"warning","data":"../package.json: No license field"} +{"type":"warning","data":"vscode-web@X.X.X: No license field"} +[XX:XX:XX] 'compile' errored after ?s +[XX:XX:XX] Error: Found 1 errors at Stream. (/vscode/build/lib/reporter.js:74:29) at _end (/vscode/node_modules/through/index.js:65:9) at Stream.stream.end (/vscode/node_modules/through/index.js:74:5) - at Stream.onend (internal/streams/legacy.js:42:10) - at Stream.emit (events.js:203:15) - at Stream.EventEmitter.emit (domain.js:466:23) - at drain (/vscode/node_modules/through/index.js:34:23) - at Stream.stream.queue.stream.push (/vscode/node_modules/through/index.js:45:5) - at Stream.end (/vscode/node_modules/through/index.js:15:35) - at _end (/vscode/node_modules/through/index.js:65:9) + at StreamFilter.onend (/vscode/node_modules/readable-stream/lib/_stream_readable.js:570:10) + at Object.onceWrapper (events.js:286:20) + at StreamFilter.emit (events.js:203:15) + at StreamFilter.EventEmitter.emit (domain.js:466:23) + at endReadableNT (/vscode/node_modules/readable-stream/lib/_stream_readable.js:992:12) + at process._tickCallback (internal/process/next_tick.js:63:19) error Command failed with exit code 1. diff --git a/tests/cases/docker/office-ui-fabric/Dockerfile b/tests/cases/docker/office-ui-fabric/Dockerfile index 718289fabe3..e31dc713ec2 100644 --- a/tests/cases/docker/office-ui-fabric/Dockerfile +++ b/tests/cases/docker/office-ui-fabric/Dockerfile @@ -1,20 +1,21 @@ FROM node:current -RUN npm install -g @microsoft/rush +RUN npm install -g yarn lerna RUN git clone https://github.com/OfficeDev/office-ui-fabric-react.git /office-ui-fabric-react WORKDIR /office-ui-fabric-react RUN git pull -RUN rush update +COPY --from=typescript/typescript /typescript/typescript-*.tgz typescript.tgz +# Sync up all TS versions used internally to the new one WORKDIR /office-ui-fabric-react/scripts -# Sync up all TS versions used internally so they're all linked from a known location -RUN rush add -p "typescript@3.5.1" --exact --dev -m -# Relink installed TSes to built TS -WORKDIR /office-ui-fabric-react/common/temp/node_modules/.registry.npmjs.org/typescript/3.5.1/node_modules -RUN rm -rf typescript -COPY --from=typescript/typescript /typescript/typescript-*.tgz /typescript.tgz -RUN mkdir /typescript -RUN tar -xzvf /typescript.tgz -C /typescript -RUN ln -s /typescript/package ./typescript -RUN npm i -g /typescript.tgz +RUN yarn add typescript@../typescript.tgz --exact --dev --ignore-scripts +WORKDIR /office-ui-fabric-react/packages/tsx-editor +RUN yarn add typescript@../../typescript.tgz --exact --ignore-scripts +WORKDIR /office-ui-fabric-react/packages/migration +RUN yarn add typescript@../../typescript.tgz --exact --ignore-scripts +WORKDIR /office-ui-fabric-react/apps/vr-tests +RUN yarn add typescript@../../typescript.tgz --exact --ignore-scripts +WORKDIR /office-ui-fabric-react/apps/todo-app +RUN yarn add typescript@../../typescript.tgz --exact --ignore-scripts WORKDIR /office-ui-fabric-react -ENTRYPOINT [ "rush" ] -CMD [ "rebuild", "--parallelism", "1" ] \ No newline at end of file +RUN yarn +ENTRYPOINT [ "lerna" ] +CMD [ "run", "build", "--stream", "--concurrency", "1", "--", "--production", "--lint" ] \ No newline at end of file diff --git a/tests/cases/docker/vscode/Dockerfile b/tests/cases/docker/vscode/Dockerfile index d20e2e8d622..b0ece263d54 100644 --- a/tests/cases/docker/vscode/Dockerfile +++ b/tests/cases/docker/vscode/Dockerfile @@ -1,4 +1,4 @@ -# vscode only supports node 8 :( +# vscode only supports older node FROM node:10 RUN apt-get update RUN apt-get install libsecret-1-dev libx11-dev libxkbfile-dev -y @@ -7,12 +7,12 @@ RUN git clone https://github.com/microsoft/vscode.git /vscode WORKDIR /vscode RUN git pull COPY --from=typescript/typescript /typescript/typescript-*.tgz /typescript.tgz -RUN mkdir /typescript -RUN tar -xzvf /typescript.tgz -C /typescript WORKDIR /vscode/build -RUN yarn add typescript@/typescript/package +RUN yarn add typescript@/typescript.tgz +WORKDIR /vscode/extensions +RUN yarn add typescript@/typescript.tgz WORKDIR /vscode -RUN yarn add typescript@/typescript/package +RUN yarn add typescript@/typescript.tgz RUN yarn ENTRYPOINT [ "yarn" ] # Build diff --git a/tests/cases/user/prettier/prettier b/tests/cases/user/prettier/prettier index 7f938c71ffd..1e471a00796 160000 --- a/tests/cases/user/prettier/prettier +++ b/tests/cases/user/prettier/prettier @@ -1 +1 @@ -Subproject commit 7f938c71ffda293eb1b69adf8bd12b7c11f9113b +Subproject commit 1e471a007968b7490563b91ed6909ae6046f3fe8 From aa12ec440c9fcd1e74576c615cd3bf889fcc74db Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 25 Jul 2019 09:47:57 -0700 Subject: [PATCH 24/30] Fix smart select on last blank line of file (#32544) * Fix SmartSelection on last blank line of file * Add baseline --- src/services/smartSelection.ts | 7 +++++++ .../reference/smartSelection_lastBlankLine.baseline | 5 +++++ tests/cases/fourslash/smartSelection_lastBlankLine.ts | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 tests/baselines/reference/smartSelection_lastBlankLine.baseline create mode 100644 tests/cases/fourslash/smartSelection_lastBlankLine.ts diff --git a/src/services/smartSelection.ts b/src/services/smartSelection.ts index d0423ce031e..3765c39ed7a 100644 --- a/src/services/smartSelection.ts +++ b/src/services/smartSelection.ts @@ -64,6 +64,13 @@ namespace ts.SmartSelectionRange { parentNode = node; break; } + + // If we made it to the end of the for loop, we’re done. + // In practice, I’ve only seen this happen at the very end + // of a SourceFile. + if (i === children.length - 1) { + break outer; + } } } diff --git a/tests/baselines/reference/smartSelection_lastBlankLine.baseline b/tests/baselines/reference/smartSelection_lastBlankLine.baseline new file mode 100644 index 00000000000..3cbad44aac4 --- /dev/null +++ b/tests/baselines/reference/smartSelection_lastBlankLine.baseline @@ -0,0 +1,5 @@ +class C {} +/**/ + + +class C {}↲ diff --git a/tests/cases/fourslash/smartSelection_lastBlankLine.ts b/tests/cases/fourslash/smartSelection_lastBlankLine.ts new file mode 100644 index 00000000000..2f5cc3f07fc --- /dev/null +++ b/tests/cases/fourslash/smartSelection_lastBlankLine.ts @@ -0,0 +1,5 @@ +/// +////class C {} +/////**/ + +verify.baselineSmartSelection(); From 772bee5e84f80a7e76c623b1c39d1eb80d8e9b4a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 25 Jul 2019 10:23:03 -0700 Subject: [PATCH 25/30] Property assignment uses parent type annotation (#32553) * Property assignment uses parent type annotation First draft, will write full explanation later. Also makes sure that jsdoc is ignored in TS. It was not before. * Update baselines --- src/compiler/checker.ts | 25 +++++++---- .../expandoFunctionContextualTypes.types | 2 +- .../expandoFunctionContextualTypesJs.types | 2 +- .../propertyAssignmentUseParentType1.js | 26 +++++++++++ .../propertyAssignmentUseParentType1.symbols | 35 +++++++++++++++ .../propertyAssignmentUseParentType1.types | 44 +++++++++++++++++++ ...ropertyAssignmentUseParentType2.errors.txt | 24 ++++++++++ .../propertyAssignmentUseParentType2.symbols | 30 +++++++++++++ .../propertyAssignmentUseParentType2.types | 42 ++++++++++++++++++ .../salsa/propertyAssignmentUseParentType1.ts | 13 ++++++ .../salsa/propertyAssignmentUseParentType2.ts | 18 ++++++++ 11 files changed, 250 insertions(+), 11 deletions(-) create mode 100644 tests/baselines/reference/propertyAssignmentUseParentType1.js create mode 100644 tests/baselines/reference/propertyAssignmentUseParentType1.symbols create mode 100644 tests/baselines/reference/propertyAssignmentUseParentType1.types create mode 100644 tests/baselines/reference/propertyAssignmentUseParentType2.errors.txt create mode 100644 tests/baselines/reference/propertyAssignmentUseParentType2.symbols create mode 100644 tests/baselines/reference/propertyAssignmentUseParentType2.types create mode 100644 tests/cases/conformance/salsa/propertyAssignmentUseParentType1.ts create mode 100644 tests/cases/conformance/salsa/propertyAssignmentUseParentType2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f56f56223cf..2f466267f9d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5396,7 +5396,7 @@ namespace ts { return undefined; } - function getWidenedTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol?: Symbol) { + function getWidenedTypeForAssignmentDeclaration(symbol: Symbol, resolvedSymbol?: Symbol) { // function/class/{} initializers are themselves containers, so they won't merge in the same way as other initializers const container = getAssignedExpandoInitializer(symbol.valueDeclaration); if (container) { @@ -5429,7 +5429,7 @@ namespace ts { } } if (!isCallExpression(expression)) { - jsdocType = getJSDocTypeFromAssignmentDeclaration(jsdocType, expression, symbol, declaration); + jsdocType = getAnnotatedTypeForAssignmentDeclaration(jsdocType, expression, symbol, declaration); } if (!jsdocType) { (types || (types = [])).push((isBinaryExpression(expression) || isCallExpression(expression)) ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) : neverType); @@ -5478,8 +5478,8 @@ namespace ts { return type; } - function getJSDocTypeFromAssignmentDeclaration(declaredType: Type | undefined, expression: Expression, _symbol: Symbol, declaration: Declaration) { - const typeNode = getJSDocType(expression.parent); + function getAnnotatedTypeForAssignmentDeclaration(declaredType: Type | undefined, expression: Expression, symbol: Symbol, declaration: Declaration) { + const typeNode = getEffectiveTypeAnnotationNode(expression.parent); if (typeNode) { const type = getWidenedType(getTypeFromTypeNode(typeNode)); if (!declaredType) { @@ -5489,6 +5489,13 @@ namespace ts { errorNextVariableOrPropertyDeclarationMustHaveSameType(/*firstDeclaration*/ undefined, declaredType, declaration, type); } } + if (symbol.parent) { + const typeNode = getEffectiveTypeAnnotationNode(symbol.parent.valueDeclaration); + if (typeNode) { + return getTypeOfPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName); + } + } + return declaredType; } @@ -5783,7 +5790,7 @@ namespace ts { } else if (isInJSFile(declaration) && (isCallExpression(declaration) || isBinaryExpression(declaration) || isPropertyAccessExpression(declaration) && isBinaryExpression(declaration.parent))) { - type = getWidenedTypeFromAssignmentDeclaration(symbol); + type = getWidenedTypeForAssignmentDeclaration(symbol); } else if (isJSDocPropertyLikeTag(declaration) || isPropertyAccessExpression(declaration) @@ -5798,7 +5805,7 @@ namespace ts { return getTypeOfFuncClassEnumModule(symbol); } type = isBinaryExpression(declaration.parent) ? - getWidenedTypeFromAssignmentDeclaration(symbol) : + getWidenedTypeForAssignmentDeclaration(symbol) : tryGetTypeFromEffectiveTypeNode(declaration) || anyType; } else if (isPropertyAssignment(declaration)) { @@ -5969,7 +5976,7 @@ namespace ts { } else if (declaration.kind === SyntaxKind.BinaryExpression || declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) { - return getWidenedTypeFromAssignmentDeclaration(symbol); + return getWidenedTypeForAssignmentDeclaration(symbol); } else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) { const resolvedModule = resolveExternalModuleSymbol(symbol); @@ -5978,7 +5985,7 @@ namespace ts { return errorType; } const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!); - const type = getWidenedTypeFromAssignmentDeclaration(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule); + const type = getWidenedTypeForAssignmentDeclaration(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule); if (!popTypeResolution()) { return reportCircularityError(symbol); } @@ -19157,7 +19164,7 @@ namespace ts { } /** - * Woah! Do you really want to use this function? + * Whoa! Do you really want to use this function? * * Unless you're trying to get the *non-apparent* type for a * value-literal type or you're authoring relevant portions of this algorithm, diff --git a/tests/baselines/reference/expandoFunctionContextualTypes.types b/tests/baselines/reference/expandoFunctionContextualTypes.types index e1eca92659c..915b168776f 100644 --- a/tests/baselines/reference/expandoFunctionContextualTypes.types +++ b/tests/baselines/reference/expandoFunctionContextualTypes.types @@ -12,7 +12,7 @@ interface StatelessComponent

{ const MyComponent: StatelessComponent = () => null as any; >MyComponent : StatelessComponent ->() => null as any : { (): any; defaultProps: { color: "red"; }; } +>() => null as any : { (): any; defaultProps: Partial; } >null as any : any >null : null diff --git a/tests/baselines/reference/expandoFunctionContextualTypesJs.types b/tests/baselines/reference/expandoFunctionContextualTypesJs.types index 081c57c0dac..82442a9db4a 100644 --- a/tests/baselines/reference/expandoFunctionContextualTypesJs.types +++ b/tests/baselines/reference/expandoFunctionContextualTypesJs.types @@ -10,7 +10,7 @@ */ const MyComponent = () => /* @type {any} */(null); >MyComponent : { (): any; defaultProps?: Partial<{ color: "red" | "blue"; }>; } ->() => /* @type {any} */(null) : { (): any; defaultProps: { color: "red"; }; } +>() => /* @type {any} */(null) : { (): any; defaultProps: Partial<{ color: "red" | "blue"; }>; } >(null) : null >null : null diff --git a/tests/baselines/reference/propertyAssignmentUseParentType1.js b/tests/baselines/reference/propertyAssignmentUseParentType1.js new file mode 100644 index 00000000000..5e839a31da4 --- /dev/null +++ b/tests/baselines/reference/propertyAssignmentUseParentType1.js @@ -0,0 +1,26 @@ +//// [propertyAssignmentUseParentType1.ts] +interface N { + (): boolean + num: 123; +} +export const interfaced: N = () => true; +interfaced.num = 123; + +export const inlined: { (): boolean; nun: 456 } = () => true; +inlined.nun = 456; + +export const ignoreJsdoc = () => true; +/** @type {string} make sure to ignore jsdoc! */ +ignoreJsdoc.extra = 111 + + +//// [propertyAssignmentUseParentType1.js] +"use strict"; +exports.__esModule = true; +exports.interfaced = function () { return true; }; +exports.interfaced.num = 123; +exports.inlined = function () { return true; }; +exports.inlined.nun = 456; +exports.ignoreJsdoc = function () { return true; }; +/** @type {string} make sure to ignore jsdoc! */ +exports.ignoreJsdoc.extra = 111; diff --git a/tests/baselines/reference/propertyAssignmentUseParentType1.symbols b/tests/baselines/reference/propertyAssignmentUseParentType1.symbols new file mode 100644 index 00000000000..081e2f12604 --- /dev/null +++ b/tests/baselines/reference/propertyAssignmentUseParentType1.symbols @@ -0,0 +1,35 @@ +=== tests/cases/conformance/salsa/propertyAssignmentUseParentType1.ts === +interface N { +>N : Symbol(N, Decl(propertyAssignmentUseParentType1.ts, 0, 0)) + + (): boolean + num: 123; +>num : Symbol(N.num, Decl(propertyAssignmentUseParentType1.ts, 1, 15)) +} +export const interfaced: N = () => true; +>interfaced : Symbol(interfaced, Decl(propertyAssignmentUseParentType1.ts, 4, 12), Decl(propertyAssignmentUseParentType1.ts, 4, 40)) +>N : Symbol(N, Decl(propertyAssignmentUseParentType1.ts, 0, 0)) + +interfaced.num = 123; +>interfaced.num : Symbol(N.num, Decl(propertyAssignmentUseParentType1.ts, 1, 15)) +>interfaced : Symbol(interfaced, Decl(propertyAssignmentUseParentType1.ts, 4, 12), Decl(propertyAssignmentUseParentType1.ts, 4, 40)) +>num : Symbol(N.num, Decl(propertyAssignmentUseParentType1.ts, 1, 15)) + +export const inlined: { (): boolean; nun: 456 } = () => true; +>inlined : Symbol(inlined, Decl(propertyAssignmentUseParentType1.ts, 7, 12), Decl(propertyAssignmentUseParentType1.ts, 7, 61)) +>nun : Symbol(nun, Decl(propertyAssignmentUseParentType1.ts, 7, 36)) + +inlined.nun = 456; +>inlined.nun : Symbol(nun, Decl(propertyAssignmentUseParentType1.ts, 7, 36)) +>inlined : Symbol(inlined, Decl(propertyAssignmentUseParentType1.ts, 7, 12), Decl(propertyAssignmentUseParentType1.ts, 7, 61)) +>nun : Symbol(nun, Decl(propertyAssignmentUseParentType1.ts, 7, 36)) + +export const ignoreJsdoc = () => true; +>ignoreJsdoc : Symbol(ignoreJsdoc, Decl(propertyAssignmentUseParentType1.ts, 10, 12), Decl(propertyAssignmentUseParentType1.ts, 10, 38)) + +/** @type {string} make sure to ignore jsdoc! */ +ignoreJsdoc.extra = 111 +>ignoreJsdoc.extra : Symbol(ignoreJsdoc.extra, Decl(propertyAssignmentUseParentType1.ts, 10, 38)) +>ignoreJsdoc : Symbol(ignoreJsdoc, Decl(propertyAssignmentUseParentType1.ts, 10, 12), Decl(propertyAssignmentUseParentType1.ts, 10, 38)) +>extra : Symbol(ignoreJsdoc.extra, Decl(propertyAssignmentUseParentType1.ts, 10, 38)) + diff --git a/tests/baselines/reference/propertyAssignmentUseParentType1.types b/tests/baselines/reference/propertyAssignmentUseParentType1.types new file mode 100644 index 00000000000..f3bd5010b20 --- /dev/null +++ b/tests/baselines/reference/propertyAssignmentUseParentType1.types @@ -0,0 +1,44 @@ +=== tests/cases/conformance/salsa/propertyAssignmentUseParentType1.ts === +interface N { + (): boolean + num: 123; +>num : 123 +} +export const interfaced: N = () => true; +>interfaced : N +>() => true : { (): true; num: 123; } +>true : true + +interfaced.num = 123; +>interfaced.num = 123 : 123 +>interfaced.num : 123 +>interfaced : N +>num : 123 +>123 : 123 + +export const inlined: { (): boolean; nun: 456 } = () => true; +>inlined : { (): boolean; nun: 456; } +>nun : 456 +>() => true : { (): true; nun: 456; } +>true : true + +inlined.nun = 456; +>inlined.nun = 456 : 456 +>inlined.nun : 456 +>inlined : { (): boolean; nun: 456; } +>nun : 456 +>456 : 456 + +export const ignoreJsdoc = () => true; +>ignoreJsdoc : { (): boolean; extra: number; } +>() => true : { (): boolean; extra: number; } +>true : true + +/** @type {string} make sure to ignore jsdoc! */ +ignoreJsdoc.extra = 111 +>ignoreJsdoc.extra = 111 : 111 +>ignoreJsdoc.extra : number +>ignoreJsdoc : { (): boolean; extra: number; } +>extra : number +>111 : 111 + diff --git a/tests/baselines/reference/propertyAssignmentUseParentType2.errors.txt b/tests/baselines/reference/propertyAssignmentUseParentType2.errors.txt new file mode 100644 index 00000000000..b88e276b405 --- /dev/null +++ b/tests/baselines/reference/propertyAssignmentUseParentType2.errors.txt @@ -0,0 +1,24 @@ +tests/cases/conformance/salsa/propertyAssignmentUseParentType2.js(11,14): error TS2322: Type '{ (): boolean; nuo: 1000; }' is not assignable to type '{ (): boolean; nuo: 789; }'. + Types of property 'nuo' are incompatible. + Type '1000' is not assignable to type '789'. + + +==== tests/cases/conformance/salsa/propertyAssignmentUseParentType2.js (1 errors) ==== + /** @type {{ (): boolean; nuo: 789 }} */ + export const inlined = () => true + inlined.nuo = 789 + + /** @type {{ (): boolean; nuo: 789 }} */ + export const duplicated = () => true + /** @type {789} */ + duplicated.nuo = 789 + + /** @type {{ (): boolean; nuo: 789 }} */ + export const conflictingDuplicated = () => true + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ (): boolean; nuo: 1000; }' is not assignable to type '{ (): boolean; nuo: 789; }'. +!!! error TS2322: Types of property 'nuo' are incompatible. +!!! error TS2322: Type '1000' is not assignable to type '789'. + /** @type {1000} */ + conflictingDuplicated.nuo = 789 + \ No newline at end of file diff --git a/tests/baselines/reference/propertyAssignmentUseParentType2.symbols b/tests/baselines/reference/propertyAssignmentUseParentType2.symbols new file mode 100644 index 00000000000..93b8b9290da --- /dev/null +++ b/tests/baselines/reference/propertyAssignmentUseParentType2.symbols @@ -0,0 +1,30 @@ +=== tests/cases/conformance/salsa/propertyAssignmentUseParentType2.js === +/** @type {{ (): boolean; nuo: 789 }} */ +export const inlined = () => true +>inlined : Symbol(inlined, Decl(propertyAssignmentUseParentType2.js, 1, 12), Decl(propertyAssignmentUseParentType2.js, 1, 33)) + +inlined.nuo = 789 +>inlined.nuo : Symbol(nuo, Decl(propertyAssignmentUseParentType2.js, 0, 25)) +>inlined : Symbol(inlined, Decl(propertyAssignmentUseParentType2.js, 1, 12), Decl(propertyAssignmentUseParentType2.js, 1, 33)) +>nuo : Symbol(nuo, Decl(propertyAssignmentUseParentType2.js, 0, 25)) + +/** @type {{ (): boolean; nuo: 789 }} */ +export const duplicated = () => true +>duplicated : Symbol(duplicated, Decl(propertyAssignmentUseParentType2.js, 5, 12), Decl(propertyAssignmentUseParentType2.js, 5, 36)) + +/** @type {789} */ +duplicated.nuo = 789 +>duplicated.nuo : Symbol(nuo, Decl(propertyAssignmentUseParentType2.js, 4, 25)) +>duplicated : Symbol(duplicated, Decl(propertyAssignmentUseParentType2.js, 5, 12), Decl(propertyAssignmentUseParentType2.js, 5, 36)) +>nuo : Symbol(nuo, Decl(propertyAssignmentUseParentType2.js, 4, 25)) + +/** @type {{ (): boolean; nuo: 789 }} */ +export const conflictingDuplicated = () => true +>conflictingDuplicated : Symbol(conflictingDuplicated, Decl(propertyAssignmentUseParentType2.js, 10, 12), Decl(propertyAssignmentUseParentType2.js, 10, 47)) + +/** @type {1000} */ +conflictingDuplicated.nuo = 789 +>conflictingDuplicated.nuo : Symbol(nuo, Decl(propertyAssignmentUseParentType2.js, 9, 25)) +>conflictingDuplicated : Symbol(conflictingDuplicated, Decl(propertyAssignmentUseParentType2.js, 10, 12), Decl(propertyAssignmentUseParentType2.js, 10, 47)) +>nuo : Symbol(nuo, Decl(propertyAssignmentUseParentType2.js, 9, 25)) + diff --git a/tests/baselines/reference/propertyAssignmentUseParentType2.types b/tests/baselines/reference/propertyAssignmentUseParentType2.types new file mode 100644 index 00000000000..24118a9ee73 --- /dev/null +++ b/tests/baselines/reference/propertyAssignmentUseParentType2.types @@ -0,0 +1,42 @@ +=== tests/cases/conformance/salsa/propertyAssignmentUseParentType2.js === +/** @type {{ (): boolean; nuo: 789 }} */ +export const inlined = () => true +>inlined : { (): boolean; nuo: 789; } +>() => true : { (): boolean; nuo: 789; } +>true : true + +inlined.nuo = 789 +>inlined.nuo = 789 : 789 +>inlined.nuo : 789 +>inlined : { (): boolean; nuo: 789; } +>nuo : 789 +>789 : 789 + +/** @type {{ (): boolean; nuo: 789 }} */ +export const duplicated = () => true +>duplicated : { (): boolean; nuo: 789; } +>() => true : { (): boolean; nuo: 789; } +>true : true + +/** @type {789} */ +duplicated.nuo = 789 +>duplicated.nuo = 789 : 789 +>duplicated.nuo : 789 +>duplicated : { (): boolean; nuo: 789; } +>nuo : 789 +>789 : 789 + +/** @type {{ (): boolean; nuo: 789 }} */ +export const conflictingDuplicated = () => true +>conflictingDuplicated : { (): boolean; nuo: 789; } +>() => true : { (): boolean; nuo: 1000; } +>true : true + +/** @type {1000} */ +conflictingDuplicated.nuo = 789 +>conflictingDuplicated.nuo = 789 : 789 +>conflictingDuplicated.nuo : 789 +>conflictingDuplicated : { (): boolean; nuo: 789; } +>nuo : 789 +>789 : 789 + diff --git a/tests/cases/conformance/salsa/propertyAssignmentUseParentType1.ts b/tests/cases/conformance/salsa/propertyAssignmentUseParentType1.ts new file mode 100644 index 00000000000..500ae6f2fe3 --- /dev/null +++ b/tests/cases/conformance/salsa/propertyAssignmentUseParentType1.ts @@ -0,0 +1,13 @@ +interface N { + (): boolean + num: 123; +} +export const interfaced: N = () => true; +interfaced.num = 123; + +export const inlined: { (): boolean; nun: 456 } = () => true; +inlined.nun = 456; + +export const ignoreJsdoc = () => true; +/** @type {string} make sure to ignore jsdoc! */ +ignoreJsdoc.extra = 111 diff --git a/tests/cases/conformance/salsa/propertyAssignmentUseParentType2.ts b/tests/cases/conformance/salsa/propertyAssignmentUseParentType2.ts new file mode 100644 index 00000000000..53696abbf81 --- /dev/null +++ b/tests/cases/conformance/salsa/propertyAssignmentUseParentType2.ts @@ -0,0 +1,18 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @Filename: propertyAssignmentUseParentType2.js + +/** @type {{ (): boolean; nuo: 789 }} */ +export const inlined = () => true +inlined.nuo = 789 + +/** @type {{ (): boolean; nuo: 789 }} */ +export const duplicated = () => true +/** @type {789} */ +duplicated.nuo = 789 + +/** @type {{ (): boolean; nuo: 789 }} */ +export const conflictingDuplicated = () => true +/** @type {1000} */ +conflictingDuplicated.nuo = 789 From ee623c1ae69b46774c2779c28c3fb438f3514072 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 25 Jul 2019 11:57:23 -0700 Subject: [PATCH 26/30] Add test case before change where config project is created just to remove it --- .../unittests/tsserver/inferredProjects.ts | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/testRunner/unittests/tsserver/inferredProjects.ts b/src/testRunner/unittests/tsserver/inferredProjects.ts index 0bc14809aaa..6882f2ed5c5 100644 --- a/src/testRunner/unittests/tsserver/inferredProjects.ts +++ b/src/testRunner/unittests/tsserver/inferredProjects.ts @@ -345,5 +345,68 @@ namespace ts.projectSystem { it("inferred projects per project root with case insensitive system", () => { verifyProjectRootWithCaseSensitivity(/*useCaseSensitiveFileNames*/ false); }); + + it("should still retain configured project created while opening the file", () => { + const projectRoot = "/user/username/projects/project"; + const appFile: File = { + path: `${projectRoot}/app.ts`, + content: `const app = 20;` + }; + const config: File = { + path: `${projectRoot}/tsconfig.json`, + content: "{}" + }; + const jsFile1: File = { + path: `${projectRoot}/jsFile1.js`, + content: `const jsFile1 = 10;` + }; + const jsFile2: File = { + path: `${projectRoot}/jsFile2.js`, + content: `const jsFile2 = 10;` + }; + const host = createServerHost([appFile, libFile, config, jsFile1, jsFile2]); + const projectService = createProjectService(host); + const originalSet = projectService.configuredProjects.set; + const originalDelete = projectService.configuredProjects.delete; + const configuredCreated = createMap(); + const configuredRemoved = createMap(); + projectService.configuredProjects.set = (key, value) => { + assert.isFalse(configuredCreated.has(key)); + configuredCreated.set(key, true); + return originalSet.call(projectService.configuredProjects, key, value); + }; + projectService.configuredProjects.delete = key => { + assert.isFalse(configuredRemoved.has(key)); + configuredRemoved.set(key, true); + return originalDelete.call(projectService.configuredProjects, key); + }; + + projectService.openClientFile(jsFile1.path); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile1.path, libFile.path]); + checkConfiguredProjectCreatedAndDeleted(); + + projectService.closeClientFile(jsFile1.path); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + projectService.openClientFile(jsFile2.path); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); + checkConfiguredProjectCreatedAndDeleted(); + + projectService.openClientFile(jsFile1.path); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, libFile.path]); + checkConfiguredProjectCreatedAndDeleted(); + + function checkConfiguredProjectCreatedAndDeleted() { + assert.equal(configuredCreated.size, 1); + assert.isTrue(configuredCreated.has(config.path)); + assert.equal(configuredRemoved.size, 1); + assert.isTrue(configuredRemoved.has(config.path)); + configuredCreated.clear(); + configuredRemoved.clear(); + } + }); }); } From 10ee85c98c9027321bc88fc8e42f4d759c7c0c63 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 25 Jul 2019 12:28:09 -0700 Subject: [PATCH 27/30] Retain the configured project opened during opening client file even if opened file isnt included in that project This helps not create and remove project on every open if tsconfig file isnt referenced by any open file --- src/server/editorServices.ts | 41 ++++++++++++++----- .../unittests/tsserver/configuredProjects.ts | 14 +++---- .../unittests/tsserver/inferredProjects.ts | 40 ++++++++++++++---- src/testRunner/unittests/tsserver/projects.ts | 18 ++++++-- 4 files changed, 83 insertions(+), 30 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index df9f0e3ee01..a25256a3aec 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -284,6 +284,10 @@ namespace ts.server { configFileErrors?: ReadonlyArray; } + interface AssignProjectResult extends OpenConfiguredProjectResult { + defaultConfigProject: ConfiguredProject | undefined; + } + interface FilePropertyReader { getFileName(f: T): string; getScriptKind(f: T, extraFileExtensions?: FileExtensionInfo[]): ScriptKind; @@ -2635,10 +2639,11 @@ namespace ts.server { return info; } - private assignProjectToOpenedScriptInfo(info: ScriptInfo): OpenConfiguredProjectResult { + private assignProjectToOpenedScriptInfo(info: ScriptInfo): AssignProjectResult { let configFileName: NormalizedPath | undefined; let configFileErrors: ReadonlyArray | undefined; let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info); + let defaultConfigProject: ConfiguredProject | undefined; if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization configFileName = this.getConfigFileNameForFile(info); if (configFileName) { @@ -2659,6 +2664,7 @@ namespace ts.server { // Ensure project is ready to check if it contains opened script info updateProjectIfDirty(project); } + defaultConfigProject = project; } } @@ -2678,13 +2684,13 @@ namespace ts.server { this.assignOrphanScriptInfoToInferredProject(info, this.openFiles.get(info.path)); } Debug.assert(!info.isOrphan()); - return { configFileName, configFileErrors }; + return { configFileName, configFileErrors, defaultConfigProject }; } - private cleanupAfterOpeningFile() { + private cleanupAfterOpeningFile(toRetainConfigProjects: ConfiguredProject[] | ConfiguredProject | undefined) { // This was postponed from closeOpenFile to after opening next file, // so that we can reuse the project if we need to right away - this.removeOrphanConfiguredProjects(); + this.removeOrphanConfiguredProjects(toRetainConfigProjects); // Remove orphan inferred projects now that we have reused projects // We need to create a duplicate because we cant guarantee order after removal @@ -2705,14 +2711,22 @@ namespace ts.server { openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult { const info = this.getOrCreateOpenScriptInfo(fileName, fileContent, scriptKind, hasMixedContent, projectRootPath); - const result = this.assignProjectToOpenedScriptInfo(info); - this.cleanupAfterOpeningFile(); + const { defaultConfigProject, ...result } = this.assignProjectToOpenedScriptInfo(info); + this.cleanupAfterOpeningFile(defaultConfigProject); this.telemetryOnOpenFile(info); return result; } - private removeOrphanConfiguredProjects() { + private removeOrphanConfiguredProjects(toRetainConfiguredProjects: ConfiguredProject[] | ConfiguredProject | undefined) { const toRemoveConfiguredProjects = cloneMap(this.configuredProjects); + if (toRetainConfiguredProjects) { + if (isArray(toRetainConfiguredProjects)) { + toRetainConfiguredProjects.forEach(retainConfiguredProject); + } + else { + retainConfiguredProject(toRetainConfiguredProjects); + } + } // Do not remove configured projects that are used as original projects of other this.inferredProjects.forEach(markOriginalProjectsAsUsed); @@ -2720,7 +2734,7 @@ namespace ts.server { this.configuredProjects.forEach(project => { // If project has open ref (there are more than zero references from external project/open file), keep it alive as well as any project it references if (project.hasOpenRef()) { - toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath); + retainConfiguredProject(project); markOriginalProjectsAsUsed(project); } else { @@ -2729,7 +2743,7 @@ namespace ts.server { if (ref) { const refProject = this.configuredProjects.get(ref.sourceFile.path); if (refProject && refProject.hasOpenRef()) { - toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath); + retainConfiguredProject(project); } } }); @@ -2744,6 +2758,10 @@ namespace ts.server { project.originalConfiguredProjects.forEach((_value, configuredProjectPath) => toRemoveConfiguredProjects.delete(configuredProjectPath)); } } + + function retainConfiguredProject(project: ConfiguredProject) { + toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath); + } } private removeOrphanScriptInfos() { @@ -2886,8 +2904,9 @@ namespace ts.server { } // All the script infos now exist, so ok to go update projects for open files + let defaultConfigProjects: ConfiguredProject[] | undefined; if (openScriptInfos) { - openScriptInfos.forEach(info => this.assignProjectToOpenedScriptInfo(info)); + defaultConfigProjects = mapDefined(openScriptInfos, info => this.assignProjectToOpenedScriptInfo(info).defaultConfigProject); } // While closing files there could be open files that needed assigning new inferred projects, do it now @@ -2896,7 +2915,7 @@ namespace ts.server { } // Cleanup projects - this.cleanupAfterOpeningFile(); + this.cleanupAfterOpeningFile(defaultConfigProjects); // Telemetry forEach(openScriptInfos, info => this.telemetryOnOpenFile(info)); diff --git a/src/testRunner/unittests/tsserver/configuredProjects.ts b/src/testRunner/unittests/tsserver/configuredProjects.ts index a72c9924303..7d066cd9473 100644 --- a/src/testRunner/unittests/tsserver/configuredProjects.ts +++ b/src/testRunner/unittests/tsserver/configuredProjects.ts @@ -866,12 +866,12 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.openClientFile(file1.path); host.runQueuedTimeoutCallbacks(); - // Since there is no file open from configFile it would be closed - checkNumberOfConfiguredProjects(projectService, 0); - checkNumberOfInferredProjects(projectService, 1); + // Since file1 refers to config file as the default project, it needs to be kept alive + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); const inferredProject = projectService.inferredProjects[0]; assert.isTrue(inferredProject.containsFile(file1.path)); + assert.isFalse(projectService.configuredProjects.get(configFile.path)!.containsFile(file1.path)); }); it("should be able to handle @types if input file list is empty", () => { @@ -898,8 +898,8 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.openClientFile(f.path); - // Since no file from the configured project is open, it would be closed immediately - projectService.checkNumberOfProjects({ configuredProjects: 0, inferredProjects: 1 }); + // Since f refers to config file as the default project, it needs to be kept alive + projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 }); }); it("should tolerate invalid include files that start in subDirectory", () => { @@ -924,8 +924,8 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.openClientFile(f.path); - // Since no file from the configured project is open, it would be closed immediately - projectService.checkNumberOfProjects({ configuredProjects: 0, inferredProjects: 1 }); + // Since f refers to config file as the default project, it needs to be kept alive + projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 }); }); it("Changed module resolution reflected when specifying files list", () => { diff --git a/src/testRunner/unittests/tsserver/inferredProjects.ts b/src/testRunner/unittests/tsserver/inferredProjects.ts index 6882f2ed5c5..44ff8292acd 100644 --- a/src/testRunner/unittests/tsserver/inferredProjects.ts +++ b/src/testRunner/unittests/tsserver/inferredProjects.ts @@ -381,30 +381,54 @@ namespace ts.projectSystem { return originalDelete.call(projectService.configuredProjects, key); }; + // Do not remove config project when opening jsFile that is not present as part of config project projectService.openClientFile(jsFile1.path); - checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); checkProjectActualFiles(projectService.inferredProjects[0], [jsFile1.path, libFile.path]); - checkConfiguredProjectCreatedAndDeleted(); + const project = projectService.configuredProjects.get(config.path)!; + checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]); + checkConfiguredProjectCreatedAndNotDeleted(); + // Do not remove config project when opening jsFile that is not present as part of config project projectService.closeClientFile(jsFile1.path); - checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); projectService.openClientFile(jsFile2.path); - checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); - checkConfiguredProjectCreatedAndDeleted(); + checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]); + checkConfiguredProjectNotCreatedAndNotDeleted(); + // Do not remove config project when opening jsFile that is not present as part of config project projectService.openClientFile(jsFile1.path); + checkNumberOfProjects(projectService, { inferredProjects: 2, configuredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, libFile.path]); + checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]); + checkConfiguredProjectNotCreatedAndNotDeleted(); + + // When opening file that doesnt fall back to the config file, we remove the config project + projectService.openClientFile(libFile.path); checkNumberOfProjects(projectService, { inferredProjects: 2 }); checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, libFile.path]); - checkConfiguredProjectCreatedAndDeleted(); + checkConfiguredProjectNotCreatedButDeleted(); - function checkConfiguredProjectCreatedAndDeleted() { + function checkConfiguredProjectCreatedAndNotDeleted() { assert.equal(configuredCreated.size, 1); assert.isTrue(configuredCreated.has(config.path)); + assert.equal(configuredRemoved.size, 0); + configuredCreated.clear(); + } + + function checkConfiguredProjectNotCreatedAndNotDeleted() { + assert.equal(configuredCreated.size, 0); + assert.equal(configuredRemoved.size, 0); + } + + function checkConfiguredProjectNotCreatedButDeleted() { + assert.equal(configuredCreated.size, 0); assert.equal(configuredRemoved.size, 1); assert.isTrue(configuredRemoved.has(config.path)); - configuredCreated.clear(); configuredRemoved.clear(); } }); diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index abb21669f8a..78d22615256 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -634,13 +634,17 @@ namespace ts.projectSystem { path: "/a/main.js", content: "var y = 1" }; + const f3 = { + path: "/main.js", + content: "var y = 1" + }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ compilerOptions: { allowJs: true } }) }; - const host = createServerHost([f1, f2, config]); + const host = createServerHost([f1, f2, f3, config]); const projectService = createProjectService(host); projectService.setHostConfiguration({ extraFileExtensions: [ @@ -652,13 +656,19 @@ namespace ts.projectSystem { projectService.checkNumberOfProjects({ configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, config.path]); - // Should close configured project with next file open + // Since f2 refers to config file as the default project, it needs to be kept alive projectService.closeClientFile(f1.path); - projectService.openClientFile(f2.path); + projectService.checkNumberOfProjects({ inferredProjects: 1, configuredProjects: 1 }); + assert.isDefined(projectService.configuredProjects.get(config.path)); + checkProjectActualFiles(projectService.inferredProjects[0], [f2.path]); + + // Should close configured project with next file open + projectService.closeClientFile(f2.path); + projectService.openClientFile(f3.path); projectService.checkNumberOfProjects({ inferredProjects: 1 }); assert.isUndefined(projectService.configuredProjects.get(config.path)); - checkProjectActualFiles(projectService.inferredProjects[0], [f2.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [f3.path]); }); it("tsconfig script block support", () => { From 599e36a0685fbeebddc00e8cb36b76fb52b9f0c8 Mon Sep 17 00:00:00 2001 From: Jesse Trinity <42591254+jessetrinity@users.noreply.github.com> Date: Thu, 25 Jul 2019 21:29:12 -0700 Subject: [PATCH 28/30] Decrement line ends if they end with a carriage return. (#31220) * Decrement line ends if they end with a carriage return. * Changed handling of newlines and inlined regex operation. * fixed misname of hintSpan * added tests * revert inline of regex match and use getLineEndOfPosition * fixed lint error and changed a silly thing in tests --- src/services/outliningElementsCollector.ts | 5 ++--- .../unittests/services/hostNewLineSupport.ts | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index a23eddf0628..6e5e2b963e8 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -71,9 +71,8 @@ namespace ts.OutliningElementsCollector { function addRegionOutliningSpans(sourceFile: SourceFile, out: Push): void { const regions: OutliningSpan[] = []; const lineStarts = sourceFile.getLineStarts(); - for (let i = 0; i < lineStarts.length; i++) { - const currentLineStart = lineStarts[i]; - const lineEnd = i + 1 === lineStarts.length ? sourceFile.getEnd() : lineStarts[i + 1] - 1; + for (const currentLineStart of lineStarts) { + const lineEnd = sourceFile.getLineEndOfPosition(currentLineStart); const lineText = sourceFile.text.substring(currentLineStart, lineEnd); const result = isRegionDelimiter(lineText); if (!result || isInComment(sourceFile, currentLineStart)) { diff --git a/src/testRunner/unittests/services/hostNewLineSupport.ts b/src/testRunner/unittests/services/hostNewLineSupport.ts index cafe4813431..48bc124f3bc 100644 --- a/src/testRunner/unittests/services/hostNewLineSupport.ts +++ b/src/testRunner/unittests/services/hostNewLineSupport.ts @@ -38,6 +38,18 @@ namespace ts { verifyNewLines(content, { newLine: NewLineKind.LineFeed }); } + function verifyOutliningSpanNewLines(content: string, options: CompilerOptions) { + const ls = testLSWithFiles(options, [{ + content, + fileOptions: {}, + unitName: "input.ts" + }]); + const span = ls.getOutliningSpans("input.ts")[0]; + const textAfterSpanCollapse = content.substring(span.textSpan.start + span.textSpan.length); + assert(textAfterSpanCollapse.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines"); + assert(!textAfterSpanCollapse.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/), "expected not to find inappropriate newlines"); + } + it("should exist and respect provided compiler options", () => { verifyBothNewLines(` function foo() { @@ -45,5 +57,15 @@ namespace ts { } `); }); + + it("should respect CRLF line endings around outlining spans", () => { + verifyOutliningSpanNewLines("// comment not included\r\n// #region name\r\nlet x: string = \"x\";\r\n// #endregion name\r\n", + { newLine: NewLineKind.CarriageReturnLineFeed }); + }); + + it("should respect LF line endings around outlining spans", () => { + verifyOutliningSpanNewLines("// comment not included\n// #region name\nlet x: string = \"x\";\n// #endregion name\n\n", + { newLine: NewLineKind.LineFeed }); + }); }); } From 2a4930f4ec75e8accd78744bd02b608d0cef9e4d Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 26 Jul 2019 13:57:22 -0700 Subject: [PATCH 29/30] Bind a jsdoc enum as SymbolFlags.TypeAlias and not SymbolFlags.Enum (#32520) * Bind a jsdoc enum as SymbolFlags.TypeAlias and not SymbolFlags.Enum * Actually include an @enum tag as a declaration * Add enum tag refs into a couple more syntax kind lists * accept symbol baseline update --- src/compiler/binder.ts | 21 +++++++------ src/compiler/checker.ts | 30 +++++++------------ src/compiler/types.ts | 3 +- src/compiler/utilities.ts | 10 ++++--- src/harness/typeWriter.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 3 +- tests/baselines/reference/api/typescript.d.ts | 3 +- tests/baselines/reference/enumTag.symbols | 16 +++++----- .../enumTagCircularReference.errors.txt | 6 ++-- .../enumTagCircularReference.symbols | 2 +- .../reference/enumTagImported.symbols | 2 +- .../enumTagUseBeforeDefCrash.symbols | 2 +- .../reference/enumTagUseBeforeDefCrash.types | 2 +- tests/cases/fourslash/findAllRefs_jsEnum.ts | 2 +- tests/cases/fourslash/quickInfoJsdocEnum.ts | 5 ++-- 15 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 38d5ed24eae..d18ab45a347 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -120,7 +120,7 @@ namespace ts { let thisParentContainer: Node; // Container one level up let blockScopeContainer: Node; let lastContainer: Node; - let delayedTypeAliases: (JSDocTypedefTag | JSDocCallbackTag)[]; + let delayedTypeAliases: (JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag)[]; let seenThisKeyword: boolean; // state used by control flow analysis @@ -732,7 +732,8 @@ namespace ts { break; case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: - bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag); + case SyntaxKind.JSDocEnumTag: + bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag); break; // In source files and blocks, bind functions first to match hoisting that occurs at runtime case SyntaxKind.SourceFile: { @@ -1436,9 +1437,9 @@ namespace ts { } } - function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag) { + function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag) { node.tagName.parent = node; - if (node.fullName) { + if (node.kind !== SyntaxKind.JSDocEnumTag && node.fullName) { setParentPointers(node, node.fullName); } } @@ -1805,7 +1806,7 @@ namespace ts { currentFlow = { flags: FlowFlags.Start }; parent = typeAlias; bind(typeAlias.typeExpression); - if (!typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) { + if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) { parent = typeAlias.parent; bindBlockScopedDeclaration(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); } @@ -2319,7 +2320,8 @@ namespace ts { return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes); case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: - return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag); + case SyntaxKind.JSDocEnumTag: + return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag); } } @@ -2766,11 +2768,8 @@ namespace ts { } if (!isBindingPattern(node.name)) { - const isEnum = isInJSFile(node) && !!getJSDocEnumTag(node); - const enumFlags = (isEnum ? SymbolFlags.RegularEnum : SymbolFlags.None); - const enumExcludes = (isEnum ? SymbolFlags.RegularEnumExcludes : SymbolFlags.None); if (isBlockOrCatchScoped(node)) { - bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable | enumFlags, SymbolFlags.BlockScopedVariableExcludes | enumExcludes); + bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); } else if (isParameterDeclaration(node)) { // It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration @@ -2785,7 +2784,7 @@ namespace ts { declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes); } else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable | enumFlags, SymbolFlags.FunctionScopedVariableExcludes | enumExcludes); + declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes); } } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2f466267f9d..834fb3eccfa 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1680,6 +1680,7 @@ namespace ts { break; case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: + case SyntaxKind.JSDocEnumTag: // js type aliases do not resolve names from their host, so skip past it location = getJSDocHost(location); break; @@ -2025,7 +2026,7 @@ namespace ts { // Block-scoped variables cannot be used before their definition const declaration = find( result.declarations, - d => isBlockOrCatchScoped(d) || isClassLike(d) || (d.kind === SyntaxKind.EnumDeclaration) || isInJSFile(d) && !!getJSDocEnumTag(d)); + d => isBlockOrCatchScoped(d) || isClassLike(d) || (d.kind === SyntaxKind.EnumDeclaration)); if (declaration === undefined) return Debug.fail("Declaration to checkResolvedBlockScopedVariable is undefined"); @@ -4851,6 +4852,7 @@ namespace ts { switch (node.kind) { case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocTypedefTag: + case SyntaxKind.JSDocEnumTag: // Top-level jsdoc type aliases are considered exported // First parent is comment node, second is hosting declaration or token; we only care about those tokens or declarations whose parent is a source file return !!(node.parent && node.parent.parent && node.parent.parent.parent && isSourceFile(node.parent.parent.parent)); @@ -6156,6 +6158,7 @@ namespace ts { case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.JSDocTemplateTag: case SyntaxKind.JSDocTypedefTag: + case SyntaxKind.JSDocEnumTag: case SyntaxKind.JSDocCallbackTag: case SyntaxKind.MappedType: case SyntaxKind.ConditionalType: @@ -6489,8 +6492,10 @@ namespace ts { return errorType; } - const declaration = find(symbol.declarations, d => - isJSDocTypeAlias(d) || d.kind === SyntaxKind.TypeAliasDeclaration); + const declaration = find(symbol.declarations, isTypeAlias); + if (!declaration) { + return Debug.fail("Type alias symbol with no valid declaration found"); + } const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type; // If typeNode is missing, we will error in checkJSDocTypedefTag. let type = typeNode ? getTypeFromTypeNode(typeNode) : errorType; @@ -6507,7 +6512,7 @@ namespace ts { } else { type = errorType; - error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error(isJSDocEnumTag(declaration) ? declaration : declaration.name || declaration, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); } links.declaredType = type; } @@ -9159,21 +9164,6 @@ namespace ts { return type; } - // JS enums are 'string' or 'number', not an enum type. - const enumTag = isInJSFile(node) && symbol.valueDeclaration && getJSDocEnumTag(symbol.valueDeclaration); - if (enumTag) { - const links = getNodeLinks(enumTag); - if (!pushTypeResolution(enumTag, TypeSystemPropertyName.EnumTagType)) { - return errorType; - } - let type = enumTag.typeExpression ? getTypeFromTypeNode(enumTag.typeExpression) : errorType; - if (!popTypeResolution()) { - type = errorType; - error(node, Diagnostics.Enum_type_0_circularly_references_itself, symbolToString(symbol)); - } - return (links.resolvedEnumType = type); - } - // Get type from reference to named type that cannot be generic (enum or type parameter) const res = tryGetDeclaredTypeOfSymbol(symbol); if (res) { @@ -26409,6 +26399,7 @@ namespace ts { // A jsdoc typedef and callback are, by definition, type aliases case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: + case SyntaxKind.JSDocEnumTag: return DeclarationSpaces.ExportType; case SyntaxKind.ModuleDeclaration: return isAmbientModule(d as ModuleDeclaration) || getModuleInstanceState(d as ModuleDeclaration) !== ModuleInstanceState.NonInstantiated @@ -30325,6 +30316,7 @@ namespace ts { return checkJSDocAugmentsTag(node as JSDocAugmentsTag); case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: + case SyntaxKind.JSDocEnumTag: return checkJSDocTypeAliasTag(node as JSDocTypedefTag); case SyntaxKind.JSDocTemplateTag: return checkJSDocTemplateTag(node as JSDocTemplateTag); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 67c85147aed..099f7705f84 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2466,7 +2466,8 @@ namespace ts { kind: SyntaxKind.JSDocClassTag; } - export interface JSDocEnumTag extends JSDocTag { + export interface JSDocEnumTag extends JSDocTag, Declaration { + parent: JSDoc; kind: SyntaxKind.JSDocEnumTag; typeExpression?: JSDocTypeExpression; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f3282d43723..d13e12a6f19 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2147,11 +2147,11 @@ namespace ts { return !!name && name.escapedText === "new"; } - export function isJSDocTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag { - return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag; + export function isJSDocTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag { + return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag || node.kind === SyntaxKind.JSDocEnumTag; } - export function isTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | TypeAliasDeclaration { + export function isTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | TypeAliasDeclaration { return isJSDocTypeAlias(node) || isTypeAliasDeclaration(node); } @@ -5091,7 +5091,7 @@ namespace ts { * attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol * will be merged with) */ - function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined { + function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag | JSDocEnumTag): Identifier | undefined { const hostNode = declaration.parent.parent; if (!hostNode) { return undefined; @@ -5177,6 +5177,8 @@ namespace ts { } case SyntaxKind.JSDocTypedefTag: return getNameOfJSDocTypedef(declaration as JSDocTypedefTag); + case SyntaxKind.JSDocEnumTag: + return nameForNamelessJSDocTypedef(declaration as JSDocEnumTag); case SyntaxKind.ExportAssignment: { const { expression } = declaration as ExportAssignment; return isIdentifier(expression) ? expression : undefined; diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index b0b20c92e64..e8b4401b846 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -97,7 +97,7 @@ class TypeWriterWalker { if (!isSymbolWalk) { // Don't try to get the type of something that's already a type. // Exception for `T` in `type T = something` because that may evaluate to some interesting type. - if (ts.isPartOfTypeNode(node) || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) && !(ts.isTypeAlias(node.parent) && node.parent.name === node)) { + if (ts.isPartOfTypeNode(node) || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) && !(ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node)) { return undefined; } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index c2bad61505b..6d81a6f08ab 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1589,7 +1589,8 @@ declare namespace ts { interface JSDocClassTag extends JSDocTag { kind: SyntaxKind.JSDocClassTag; } - interface JSDocEnumTag extends JSDocTag { + interface JSDocEnumTag extends JSDocTag, Declaration { + parent: JSDoc; kind: SyntaxKind.JSDocEnumTag; typeExpression?: JSDocTypeExpression; } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 7a2559bbc22..ebd2d1471f7 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1589,7 +1589,8 @@ declare namespace ts { interface JSDocClassTag extends JSDocTag { kind: SyntaxKind.JSDocClassTag; } - interface JSDocEnumTag extends JSDocTag { + interface JSDocEnumTag extends JSDocTag, Declaration { + parent: JSDoc; kind: SyntaxKind.JSDocEnumTag; typeExpression?: JSDocTypeExpression; } diff --git a/tests/baselines/reference/enumTag.symbols b/tests/baselines/reference/enumTag.symbols index a54b9f4a3d8..87bcd6961a5 100644 --- a/tests/baselines/reference/enumTag.symbols +++ b/tests/baselines/reference/enumTag.symbols @@ -1,7 +1,7 @@ === tests/cases/conformance/jsdoc/a.js === /** @enum {string} */ const Target = { ->Target : Symbol(Target, Decl(a.js, 1, 5)) +>Target : Symbol(Target, Decl(a.js, 1, 5), Decl(a.js, 0, 4)) START: "start", >START : Symbol(START, Decl(a.js, 1, 16)) @@ -21,7 +21,7 @@ const Target = { } /** @enum number */ const Second = { ->Second : Symbol(Second, Decl(a.js, 10, 5)) +>Second : Symbol(Second, Decl(a.js, 10, 5), Decl(a.js, 9, 4)) MISTAKE: "end", >MISTAKE : Symbol(MISTAKE, Decl(a.js, 10, 16)) @@ -35,7 +35,7 @@ const Second = { } /** @enum {function(number): number} */ const Fs = { ->Fs : Symbol(Fs, Decl(a.js, 17, 5)) +>Fs : Symbol(Fs, Decl(a.js, 17, 5), Decl(a.js, 16, 4)) ADD1: n => n + 1, >ADD1 : Symbol(ADD1, Decl(a.js, 17, 12)) @@ -82,17 +82,17 @@ function consume(t,s,f) { var v = Target.START >v : Symbol(v, Decl(a.js, 35, 7)) >Target.START : Symbol(START, Decl(a.js, 1, 16)) ->Target : Symbol(Target, Decl(a.js, 1, 5)) +>Target : Symbol(Target, Decl(a.js, 1, 5), Decl(a.js, 0, 4)) >START : Symbol(START, Decl(a.js, 1, 16)) v = Target.UNKNOWN // error, can't find 'UNKNOWN' >v : Symbol(v, Decl(a.js, 35, 7)) ->Target : Symbol(Target, Decl(a.js, 1, 5)) +>Target : Symbol(Target, Decl(a.js, 1, 5), Decl(a.js, 0, 4)) v = Second.MISTAKE // meh..ok, I guess? >v : Symbol(v, Decl(a.js, 35, 7)) >Second.MISTAKE : Symbol(MISTAKE, Decl(a.js, 10, 16)) ->Second : Symbol(Second, Decl(a.js, 10, 5)) +>Second : Symbol(Second, Decl(a.js, 10, 5), Decl(a.js, 9, 4)) >MISTAKE : Symbol(MISTAKE, Decl(a.js, 10, 16)) v = 'something else' // allowed, like Typescript's classic enums and unlike its string enums @@ -105,14 +105,14 @@ function ff(s) { // element access with arbitrary string is an error only with noImplicitAny if (!Target[s]) { ->Target : Symbol(Target, Decl(a.js, 1, 5)) +>Target : Symbol(Target, Decl(a.js, 1, 5), Decl(a.js, 0, 4)) >s : Symbol(s, Decl(a.js, 41, 12)) return null } else { return Target[s] ->Target : Symbol(Target, Decl(a.js, 1, 5)) +>Target : Symbol(Target, Decl(a.js, 1, 5), Decl(a.js, 0, 4)) >s : Symbol(s, Decl(a.js, 41, 12)) } } diff --git a/tests/baselines/reference/enumTagCircularReference.errors.txt b/tests/baselines/reference/enumTagCircularReference.errors.txt index f876b5a33da..f42be3719f9 100644 --- a/tests/baselines/reference/enumTagCircularReference.errors.txt +++ b/tests/baselines/reference/enumTagCircularReference.errors.txt @@ -1,9 +1,9 @@ -tests/cases/conformance/jsdoc/bug27142.js(1,12): error TS2586: Enum type 'E' circularly references itself. +tests/cases/conformance/jsdoc/bug27142.js(1,5): error TS2456: Type alias 'E' circularly references itself. ==== tests/cases/conformance/jsdoc/bug27142.js (1 errors) ==== /** @enum {E} */ - ~ -!!! error TS2586: Enum type 'E' circularly references itself. + ~~~~~~~~~ +!!! error TS2456: Type alias 'E' circularly references itself. const E = { x: 0 }; \ No newline at end of file diff --git a/tests/baselines/reference/enumTagCircularReference.symbols b/tests/baselines/reference/enumTagCircularReference.symbols index e3c594ac9d1..1236c02e392 100644 --- a/tests/baselines/reference/enumTagCircularReference.symbols +++ b/tests/baselines/reference/enumTagCircularReference.symbols @@ -1,6 +1,6 @@ === tests/cases/conformance/jsdoc/bug27142.js === /** @enum {E} */ const E = { x: 0 }; ->E : Symbol(E, Decl(bug27142.js, 1, 5)) +>E : Symbol(E, Decl(bug27142.js, 1, 5), Decl(bug27142.js, 0, 4)) >x : Symbol(x, Decl(bug27142.js, 1, 11)) diff --git a/tests/baselines/reference/enumTagImported.symbols b/tests/baselines/reference/enumTagImported.symbols index ab9ab5eceb1..a79198aaae1 100644 --- a/tests/baselines/reference/enumTagImported.symbols +++ b/tests/baselines/reference/enumTagImported.symbols @@ -23,7 +23,7 @@ const tist = TestEnum.ADD === tests/cases/conformance/jsdoc/mod1.js === /** @enum {string} */ export const TestEnum = { ->TestEnum : Symbol(TestEnum, Decl(mod1.js, 1, 12)) +>TestEnum : Symbol(TestEnum, Decl(mod1.js, 1, 12), Decl(mod1.js, 0, 4)) ADD: 'add', >ADD : Symbol(ADD, Decl(mod1.js, 1, 25)) diff --git a/tests/baselines/reference/enumTagUseBeforeDefCrash.symbols b/tests/baselines/reference/enumTagUseBeforeDefCrash.symbols index 1cef96a9823..8ec8a90e64b 100644 --- a/tests/baselines/reference/enumTagUseBeforeDefCrash.symbols +++ b/tests/baselines/reference/enumTagUseBeforeDefCrash.symbols @@ -3,7 +3,7 @@ * @enum {number} */ var foo = { }; ->foo : Symbol(foo, Decl(bug27134.js, 3, 3)) +>foo : Symbol(foo, Decl(bug27134.js, 3, 3), Decl(bug27134.js, 1, 3)) /** * @type {foo} diff --git a/tests/baselines/reference/enumTagUseBeforeDefCrash.types b/tests/baselines/reference/enumTagUseBeforeDefCrash.types index 159781fee05..d9f800d0d03 100644 --- a/tests/baselines/reference/enumTagUseBeforeDefCrash.types +++ b/tests/baselines/reference/enumTagUseBeforeDefCrash.types @@ -3,7 +3,7 @@ * @enum {number} */ var foo = { }; ->foo : typeof foo +>foo : {} >{ } : {} /** diff --git a/tests/cases/fourslash/findAllRefs_jsEnum.ts b/tests/cases/fourslash/findAllRefs_jsEnum.ts index f9033d6c588..d492cd84de4 100644 --- a/tests/cases/fourslash/findAllRefs_jsEnum.ts +++ b/tests/cases/fourslash/findAllRefs_jsEnum.ts @@ -10,7 +10,7 @@ ////const e = [|E|].A; verify.singleReferenceGroup( -`enum E +`type E = string const E: { A: string; }`, "E"); diff --git a/tests/cases/fourslash/quickInfoJsdocEnum.ts b/tests/cases/fourslash/quickInfoJsdocEnum.ts index 9ef3b1edc78..b8264b52110 100644 --- a/tests/cases/fourslash/quickInfoJsdocEnum.ts +++ b/tests/cases/fourslash/quickInfoJsdocEnum.ts @@ -18,11 +18,10 @@ verify.noErrors(); verify.quickInfoAt("type", -`enum E`, +`type E = number`, "Doc"); verify.quickInfoAt("value", -`enum E -const E: { +`const E: { A: number; }`, "Doc"); From 3d09010dc8916446f3e7a00df7845bc982ae721f Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 26 Jul 2019 14:56:03 -0700 Subject: [PATCH 30/30] Intersect 'this' types in union signatures (#32538) * Intersect this types in union signatures * Actually update baselines --- src/compiler/checker.ts | 13 +- .../unionThisTypeInFunctions.errors.txt | 34 ++++ .../reference/unionThisTypeInFunctions.js | 4 +- .../unionThisTypeInFunctions.symbols | 2 +- .../reference/unionThisTypeInFunctions.types | 4 +- .../unionTypeCallSignatures5.errors.txt | 19 ++ .../reference/unionTypeCallSignatures5.types | 2 +- .../unionTypeCallSignatures6.errors.txt | 98 +++++++++ .../reference/unionTypeCallSignatures6.js | 69 +++++++ .../unionTypeCallSignatures6.symbols | 187 ++++++++++++++++++ .../reference/unionTypeCallSignatures6.types | 150 ++++++++++++++ .../thisType/unionThisTypeInFunctions.ts | 2 +- .../types/union/unionTypeCallSignatures6.ts | 55 ++++++ 13 files changed, 626 insertions(+), 13 deletions(-) create mode 100644 tests/baselines/reference/unionThisTypeInFunctions.errors.txt create mode 100644 tests/baselines/reference/unionTypeCallSignatures5.errors.txt create mode 100644 tests/baselines/reference/unionTypeCallSignatures6.errors.txt create mode 100644 tests/baselines/reference/unionTypeCallSignatures6.js create mode 100644 tests/baselines/reference/unionTypeCallSignatures6.symbols create mode 100644 tests/baselines/reference/unionTypeCallSignatures6.types create mode 100644 tests/cases/conformance/types/union/unionTypeCallSignatures6.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 834fb3eccfa..f8242ed6df7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7181,8 +7181,9 @@ namespace ts { } let result: Signature[] | undefined; for (let i = 0; i < signatureLists.length; i++) { - // Allow matching non-generic signatures to have excess parameters and different return types - const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true); + // Allow matching non-generic signatures to have excess parameters and different return types. + // Prefer matching this types if possible. + const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); if (!match) { return undefined; } @@ -7205,7 +7206,7 @@ namespace ts { } for (const signature of signatureLists[i]) { // Only process signatures with parameter lists that aren't already in the result list - if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true)) { + if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true)) { const unionSignatures = findMatchingSignatures(signatureLists, signature, i); if (unionSignatures) { let s = signature; @@ -7214,7 +7215,7 @@ namespace ts { let thisParameter = signature.thisParameter; const firstThisParameterOfUnionSignatures = forEach(unionSignatures, sig => sig.thisParameter); if (firstThisParameterOfUnionSignatures) { - const thisType = getUnionType(map(unionSignatures, sig => sig.thisParameter ? getTypeOfSymbol(sig.thisParameter) : anyType), UnionReduction.Subtype); + const thisType = getIntersectionType(mapDefined(unionSignatures, sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter))); thisParameter = createSymbolWithType(firstThisParameterOfUnionSignatures, thisType); } s = createUnionSignature(signature, unionSignatures); @@ -7253,8 +7254,8 @@ namespace ts { } // A signature `this` type might be a read or a write position... It's very possible that it should be invariant // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be - // permissive when calling, for now, we'll union the `this` types just like the overlapping-union-signature check does - const thisType = getUnionType([getTypeOfSymbol(left), getTypeOfSymbol(right)], UnionReduction.Subtype); + // permissive when calling, for now, we'll intersect the `this` types just like we do for param types in union signatures. + const thisType = getIntersectionType([getTypeOfSymbol(left), getTypeOfSymbol(right)]); return createSymbolWithType(left, thisType); } diff --git a/tests/baselines/reference/unionThisTypeInFunctions.errors.txt b/tests/baselines/reference/unionThisTypeInFunctions.errors.txt new file mode 100644 index 00000000000..db03a5426fb --- /dev/null +++ b/tests/baselines/reference/unionThisTypeInFunctions.errors.txt @@ -0,0 +1,34 @@ +tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts(10,5): error TS2684: The 'this' context of type 'Real | Fake' is not assignable to method's 'this' of type 'Real & Fake'. + Type 'Real' is not assignable to type 'Real & Fake'. + Type 'Real' is not assignable to type 'Fake'. + Types of property 'method' are incompatible. + Type '(this: Real, n: number) => void' is not assignable to type '(this: Fake, n: number) => void'. + The 'this' types of each signature are incompatible. + Type 'Fake' is not assignable to type 'Real'. + Types of property 'data' are incompatible. + Type 'number' is not assignable to type 'string'. + + +==== tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts (1 errors) ==== + interface Real { + method(this: this, n: number): void; + data: string; + } + interface Fake { + method(this: this, n: number): void; + data: number; + } + function test(r: Real | Fake) { + r.method(12); // error + ~ +!!! error TS2684: The 'this' context of type 'Real | Fake' is not assignable to method's 'this' of type 'Real & Fake'. +!!! error TS2684: Type 'Real' is not assignable to type 'Real & Fake'. +!!! error TS2684: Type 'Real' is not assignable to type 'Fake'. +!!! error TS2684: Types of property 'method' are incompatible. +!!! error TS2684: Type '(this: Real, n: number) => void' is not assignable to type '(this: Fake, n: number) => void'. +!!! error TS2684: The 'this' types of each signature are incompatible. +!!! error TS2684: Type 'Fake' is not assignable to type 'Real'. +!!! error TS2684: Types of property 'data' are incompatible. +!!! error TS2684: Type 'number' is not assignable to type 'string'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/unionThisTypeInFunctions.js b/tests/baselines/reference/unionThisTypeInFunctions.js index 0d4b535ff8b..dca64b6d893 100644 --- a/tests/baselines/reference/unionThisTypeInFunctions.js +++ b/tests/baselines/reference/unionThisTypeInFunctions.js @@ -8,11 +8,11 @@ interface Fake { data: number; } function test(r: Real | Fake) { - r.method(12); + r.method(12); // error } //// [unionThisTypeInFunctions.js] function test(r) { - r.method(12); + r.method(12); // error } diff --git a/tests/baselines/reference/unionThisTypeInFunctions.symbols b/tests/baselines/reference/unionThisTypeInFunctions.symbols index eada1231750..b907519626a 100644 --- a/tests/baselines/reference/unionThisTypeInFunctions.symbols +++ b/tests/baselines/reference/unionThisTypeInFunctions.symbols @@ -27,7 +27,7 @@ function test(r: Real | Fake) { >Real : Symbol(Real, Decl(unionThisTypeInFunctions.ts, 0, 0)) >Fake : Symbol(Fake, Decl(unionThisTypeInFunctions.ts, 3, 1)) - r.method(12); + r.method(12); // error >r.method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 0, 16), Decl(unionThisTypeInFunctions.ts, 4, 16)) >r : Symbol(r, Decl(unionThisTypeInFunctions.ts, 8, 14)) >method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 0, 16), Decl(unionThisTypeInFunctions.ts, 4, 16)) diff --git a/tests/baselines/reference/unionThisTypeInFunctions.types b/tests/baselines/reference/unionThisTypeInFunctions.types index 44c03d73a61..af987759a55 100644 --- a/tests/baselines/reference/unionThisTypeInFunctions.types +++ b/tests/baselines/reference/unionThisTypeInFunctions.types @@ -21,8 +21,8 @@ function test(r: Real | Fake) { >test : (r: Real | Fake) => void >r : Real | Fake - r.method(12); ->r.method(12) : void + r.method(12); // error +>r.method(12) : any >r.method : ((this: Real, n: number) => void) | ((this: Fake, n: number) => void) >r : Real | Fake >method : ((this: Real, n: number) => void) | ((this: Fake, n: number) => void) diff --git a/tests/baselines/reference/unionTypeCallSignatures5.errors.txt b/tests/baselines/reference/unionTypeCallSignatures5.errors.txt new file mode 100644 index 00000000000..2dc6ebb002b --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures5.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/types/union/unionTypeCallSignatures5.ts(12,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'never'. + + +==== tests/cases/conformance/types/union/unionTypeCallSignatures5.ts (1 errors) ==== + // #31485 + interface A { + (this: void, b?: number): void; + } + interface B { + (this: number, b?: number): void; + } + interface C { + (i: number): void; + } + declare const fn: A | B | C; + fn(0); + ~~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'never'. + \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeCallSignatures5.types b/tests/baselines/reference/unionTypeCallSignatures5.types index 53ce4ea6550..b9b5a6fbc0d 100644 --- a/tests/baselines/reference/unionTypeCallSignatures5.types +++ b/tests/baselines/reference/unionTypeCallSignatures5.types @@ -18,7 +18,7 @@ declare const fn: A | B | C; >fn : A | B | C fn(0); ->fn(0) : void +>fn(0) : any >fn : A | B | C >0 : 0 diff --git a/tests/baselines/reference/unionTypeCallSignatures6.errors.txt b/tests/baselines/reference/unionTypeCallSignatures6.errors.txt new file mode 100644 index 00000000000..51b18b204a7 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.errors.txt @@ -0,0 +1,98 @@ +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(11,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. + Type 'void' is not assignable to type 'A'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(13,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(38,4): error TS2349: This expression is not callable. + Each member of the union type 'F3 | F4' has signatures, but none of those signatures are compatible with each other. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(39,1): error TS2684: The 'this' context of type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' is not assignable to method's 'this' of type 'B'. + Property 'b' is missing in type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' but required in type 'B'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(48,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. + Type 'void' is not assignable to type 'A'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(55,1): error TS2769: No overload matches this call. + Overload 1 of 2, '(this: A & B & C): void', gave the following error. + The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B & C'. + Type 'void' is not assignable to type 'A'. + Overload 2 of 2, '(this: A & B): void', gave the following error. + The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. + Type 'void' is not assignable to type 'A'. + + +==== tests/cases/conformance/types/union/unionTypeCallSignatures6.ts (6 errors) ==== + type A = { a: string }; + type B = { b: number }; + type C = { c: string }; + type D = { d: number }; + type F0 = () => void; + + // #31547 + type F1 = (this: A) => void; + type F2 = (this: B) => void; + declare var f1: F1 | F2; + f1(); // error + ~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +!!! error TS2684: Type 'void' is not assignable to type 'A'. + declare var f2: F0 | F1; + f2(); // error + ~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A'. + + interface F3 { + (this: A): void; + (this: B): void; + } + interface F4 { + (this: C): void; + (this: D): void; + } + interface F5 { + (this: C): void; + (this: B): void; + } + + declare var x1: A & C & { + f0: F0 | F3; + f1: F1 | F3; + f2: F1 | F4; + f3: F3 | F4; + f4: F3 | F5; + } + x1.f0(); + x1.f1(); + x1.f2(); + x1.f3(); // error + ~~ +!!! error TS2349: This expression is not callable. +!!! error TS2349: Each member of the union type 'F3 | F4' has signatures, but none of those signatures are compatible with each other. + x1.f4(); // error + ~~ +!!! error TS2684: The 'this' context of type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' is not assignable to method's 'this' of type 'B'. +!!! error TS2684: Property 'b' is missing in type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' but required in type 'B'. +!!! related TS2728 tests/cases/conformance/types/union/unionTypeCallSignatures6.ts:2:12: 'b' is declared here. + + declare var x2: A & B & { + f4: F3 | F5; + } + x2.f4(); + + type F6 = (this: A & B) => void; + declare var f3: F1 | F6; + f3(); // error + ~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +!!! error TS2684: Type 'void' is not assignable to type 'A'. + + interface F7 { + (this: A & B & C): void; + (this: A & B): void; + } + declare var f4: F6 | F7; + f4(); // error + ~~~~ +!!! error TS2769: No overload matches this call. +!!! error TS2769: Overload 1 of 2, '(this: A & B & C): void', gave the following error. +!!! error TS2769: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B & C'. +!!! error TS2769: Type 'void' is not assignable to type 'A'. +!!! error TS2769: Overload 2 of 2, '(this: A & B): void', gave the following error. +!!! error TS2769: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +!!! error TS2769: Type 'void' is not assignable to type 'A'. + \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeCallSignatures6.js b/tests/baselines/reference/unionTypeCallSignatures6.js new file mode 100644 index 00000000000..32e0518cbb8 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.js @@ -0,0 +1,69 @@ +//// [unionTypeCallSignatures6.ts] +type A = { a: string }; +type B = { b: number }; +type C = { c: string }; +type D = { d: number }; +type F0 = () => void; + +// #31547 +type F1 = (this: A) => void; +type F2 = (this: B) => void; +declare var f1: F1 | F2; +f1(); // error +declare var f2: F0 | F1; +f2(); // error + +interface F3 { + (this: A): void; + (this: B): void; +} +interface F4 { + (this: C): void; + (this: D): void; +} +interface F5 { + (this: C): void; + (this: B): void; +} + +declare var x1: A & C & { + f0: F0 | F3; + f1: F1 | F3; + f2: F1 | F4; + f3: F3 | F4; + f4: F3 | F5; +} +x1.f0(); +x1.f1(); +x1.f2(); +x1.f3(); // error +x1.f4(); // error + +declare var x2: A & B & { + f4: F3 | F5; +} +x2.f4(); + +type F6 = (this: A & B) => void; +declare var f3: F1 | F6; +f3(); // error + +interface F7 { + (this: A & B & C): void; + (this: A & B): void; +} +declare var f4: F6 | F7; +f4(); // error + + +//// [unionTypeCallSignatures6.js] +f1(); // error +f2(); // error +x1.f0(); +x1.f1(); +x1.f2(); +x1.f3(); // error +x1.f4(); // error +x2.f4(); +f3(); // error +f4(); // error diff --git a/tests/baselines/reference/unionTypeCallSignatures6.symbols b/tests/baselines/reference/unionTypeCallSignatures6.symbols new file mode 100644 index 00000000000..87d1928f069 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.symbols @@ -0,0 +1,187 @@ +=== tests/cases/conformance/types/union/unionTypeCallSignatures6.ts === +type A = { a: string }; +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>a : Symbol(a, Decl(unionTypeCallSignatures6.ts, 0, 10)) + +type B = { b: number }; +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +>b : Symbol(b, Decl(unionTypeCallSignatures6.ts, 1, 10)) + +type C = { c: string }; +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) +>c : Symbol(c, Decl(unionTypeCallSignatures6.ts, 2, 10)) + +type D = { d: number }; +>D : Symbol(D, Decl(unionTypeCallSignatures6.ts, 2, 23)) +>d : Symbol(d, Decl(unionTypeCallSignatures6.ts, 3, 10)) + +type F0 = () => void; +>F0 : Symbol(F0, Decl(unionTypeCallSignatures6.ts, 3, 23)) + +// #31547 +type F1 = (this: A) => void; +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 7, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) + +type F2 = (this: B) => void; +>F2 : Symbol(F2, Decl(unionTypeCallSignatures6.ts, 7, 28)) +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 8, 11)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) + +declare var f1: F1 | F2; +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 9, 11)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F2 : Symbol(F2, Decl(unionTypeCallSignatures6.ts, 7, 28)) + +f1(); // error +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 9, 11)) + +declare var f2: F0 | F1; +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 11, 11)) +>F0 : Symbol(F0, Decl(unionTypeCallSignatures6.ts, 3, 23)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) + +f2(); // error +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 11, 11)) + +interface F3 { +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) + + (this: A): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 15, 3)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) + + (this: B): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 16, 3)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +} +interface F4 { +>F4 : Symbol(F4, Decl(unionTypeCallSignatures6.ts, 17, 1)) + + (this: C): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 19, 3)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + (this: D): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 20, 3)) +>D : Symbol(D, Decl(unionTypeCallSignatures6.ts, 2, 23)) +} +interface F5 { +>F5 : Symbol(F5, Decl(unionTypeCallSignatures6.ts, 21, 1)) + + (this: C): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 23, 3)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + (this: B): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 24, 3)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +} + +declare var x1: A & C & { +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + f0: F0 | F3; +>f0 : Symbol(f0, Decl(unionTypeCallSignatures6.ts, 27, 25)) +>F0 : Symbol(F0, Decl(unionTypeCallSignatures6.ts, 3, 23)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) + + f1: F1 | F3; +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 28, 14)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) + + f2: F1 | F4; +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 29, 14)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F4 : Symbol(F4, Decl(unionTypeCallSignatures6.ts, 17, 1)) + + f3: F3 | F4; +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 30, 14)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) +>F4 : Symbol(F4, Decl(unionTypeCallSignatures6.ts, 17, 1)) + + f4: F3 | F5; +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 31, 14)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) +>F5 : Symbol(F5, Decl(unionTypeCallSignatures6.ts, 21, 1)) +} +x1.f0(); +>x1.f0 : Symbol(f0, Decl(unionTypeCallSignatures6.ts, 27, 25)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f0 : Symbol(f0, Decl(unionTypeCallSignatures6.ts, 27, 25)) + +x1.f1(); +>x1.f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 28, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 28, 14)) + +x1.f2(); +>x1.f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 29, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 29, 14)) + +x1.f3(); // error +>x1.f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 30, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 30, 14)) + +x1.f4(); // error +>x1.f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 31, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 31, 14)) + +declare var x2: A & B & { +>x2 : Symbol(x2, Decl(unionTypeCallSignatures6.ts, 40, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) + + f4: F3 | F5; +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 40, 25)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) +>F5 : Symbol(F5, Decl(unionTypeCallSignatures6.ts, 21, 1)) +} +x2.f4(); +>x2.f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 40, 25)) +>x2 : Symbol(x2, Decl(unionTypeCallSignatures6.ts, 40, 11)) +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 40, 25)) + +type F6 = (this: A & B) => void; +>F6 : Symbol(F6, Decl(unionTypeCallSignatures6.ts, 43, 8)) +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 45, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) + +declare var f3: F1 | F6; +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 46, 11)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F6 : Symbol(F6, Decl(unionTypeCallSignatures6.ts, 43, 8)) + +f3(); // error +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 46, 11)) + +interface F7 { +>F7 : Symbol(F7, Decl(unionTypeCallSignatures6.ts, 47, 5)) + + (this: A & B & C): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 50, 3)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + (this: A & B): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 51, 3)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +} +declare var f4: F6 | F7; +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 53, 11)) +>F6 : Symbol(F6, Decl(unionTypeCallSignatures6.ts, 43, 8)) +>F7 : Symbol(F7, Decl(unionTypeCallSignatures6.ts, 47, 5)) + +f4(); // error +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 53, 11)) + diff --git a/tests/baselines/reference/unionTypeCallSignatures6.types b/tests/baselines/reference/unionTypeCallSignatures6.types new file mode 100644 index 00000000000..930c91b1109 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.types @@ -0,0 +1,150 @@ +=== tests/cases/conformance/types/union/unionTypeCallSignatures6.ts === +type A = { a: string }; +>A : A +>a : string + +type B = { b: number }; +>B : B +>b : number + +type C = { c: string }; +>C : C +>c : string + +type D = { d: number }; +>D : D +>d : number + +type F0 = () => void; +>F0 : F0 + +// #31547 +type F1 = (this: A) => void; +>F1 : F1 +>this : A + +type F2 = (this: B) => void; +>F2 : F2 +>this : B + +declare var f1: F1 | F2; +>f1 : F1 | F2 + +f1(); // error +>f1() : any +>f1 : F1 | F2 + +declare var f2: F0 | F1; +>f2 : F1 | F0 + +f2(); // error +>f2() : any +>f2 : F1 | F0 + +interface F3 { + (this: A): void; +>this : A + + (this: B): void; +>this : B +} +interface F4 { + (this: C): void; +>this : C + + (this: D): void; +>this : D +} +interface F5 { + (this: C): void; +>this : C + + (this: B): void; +>this : B +} + +declare var x1: A & C & { +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } + + f0: F0 | F3; +>f0 : F0 | F3 + + f1: F1 | F3; +>f1 : F1 | F3 + + f2: F1 | F4; +>f2 : F1 | F4 + + f3: F3 | F4; +>f3 : F3 | F4 + + f4: F3 | F5; +>f4 : F3 | F5 +} +x1.f0(); +>x1.f0() : void +>x1.f0 : F0 | F3 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f0 : F0 | F3 + +x1.f1(); +>x1.f1() : void +>x1.f1 : F1 | F3 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f1 : F1 | F3 + +x1.f2(); +>x1.f2() : void +>x1.f2 : F1 | F4 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f2 : F1 | F4 + +x1.f3(); // error +>x1.f3() : any +>x1.f3 : F3 | F4 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f3 : F3 | F4 + +x1.f4(); // error +>x1.f4() : any +>x1.f4 : F3 | F5 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f4 : F3 | F5 + +declare var x2: A & B & { +>x2 : A & B & { f4: F3 | F5; } + + f4: F3 | F5; +>f4 : F3 | F5 +} +x2.f4(); +>x2.f4() : void +>x2.f4 : F3 | F5 +>x2 : A & B & { f4: F3 | F5; } +>f4 : F3 | F5 + +type F6 = (this: A & B) => void; +>F6 : F6 +>this : A & B + +declare var f3: F1 | F6; +>f3 : F1 | F6 + +f3(); // error +>f3() : any +>f3 : F1 | F6 + +interface F7 { + (this: A & B & C): void; +>this : A & B & C + + (this: A & B): void; +>this : A & B +} +declare var f4: F6 | F7; +>f4 : F6 | F7 + +f4(); // error +>f4() : any +>f4 : F6 | F7 + diff --git a/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts b/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts index 4f74058cc48..a35019d372e 100644 --- a/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts +++ b/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts @@ -7,5 +7,5 @@ interface Fake { data: number; } function test(r: Real | Fake) { - r.method(12); + r.method(12); // error } diff --git a/tests/cases/conformance/types/union/unionTypeCallSignatures6.ts b/tests/cases/conformance/types/union/unionTypeCallSignatures6.ts new file mode 100644 index 00000000000..0fe98847205 --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeCallSignatures6.ts @@ -0,0 +1,55 @@ +type A = { a: string }; +type B = { b: number }; +type C = { c: string }; +type D = { d: number }; +type F0 = () => void; + +// #31547 +type F1 = (this: A) => void; +type F2 = (this: B) => void; +declare var f1: F1 | F2; +f1(); // error +declare var f2: F0 | F1; +f2(); // error + +interface F3 { + (this: A): void; + (this: B): void; +} +interface F4 { + (this: C): void; + (this: D): void; +} +interface F5 { + (this: C): void; + (this: B): void; +} + +declare var x1: A & C & { + f0: F0 | F3; + f1: F1 | F3; + f2: F1 | F4; + f3: F3 | F4; + f4: F3 | F5; +} +x1.f0(); +x1.f1(); +x1.f2(); +x1.f3(); // error +x1.f4(); // error + +declare var x2: A & B & { + f4: F3 | F5; +} +x2.f4(); + +type F6 = (this: A & B) => void; +declare var f3: F1 | F6; +f3(); // error + +interface F7 { + (this: A & B & C): void; + (this: A & B): void; +} +declare var f4: F6 | F7; +f4(); // error