diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b0ccb426eb2..83cc54e1acc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3217,8 +3217,8 @@ module ts { return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined); } - function compareTypes(source: Type, target: Type): number { - return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? -1 : 0; + function compareTypes(source: Type, target: Type): Ternary { + return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False; } function isTypeSubtypeOf(source: Type, target: Type): boolean { @@ -3270,7 +3270,7 @@ module ts { } addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, program.getCompilerHost().getNewLine())); } - return result !== 0; + return result !== Ternary.False; function reportError(message: DiagnosticMessage, arg0?: string, arg1?: string, arg2?: string): void { errorInfo = chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2); @@ -3418,11 +3418,13 @@ module ts { if (depth > 0) { for (var i = 0; i < depth; i++) { // If source and target are already being compared, consider them related with assumptions - if (source === sourceStack[i] && target === targetStack[i]) return Ternary.Maybe; + if (source === sourceStack[i] && target === targetStack[i]) { + return Ternary.Maybe; + } } if (depth === 100) { overflow = true; - return 0; + return Ternary.False; } } else { @@ -3766,7 +3768,7 @@ module ts { } function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean { - return compareProperties(sourceProp, targetProp, compareTypes) !== 0; + return compareProperties(sourceProp, targetProp, compareTypes) !== Ternary.False; } function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary { @@ -3785,14 +3787,13 @@ module ts { if (getTargetSymbol(sourceProp) !== getTargetSymbol(targetProp)) { return Ternary.False; } - return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); } else { if (isOptionalProperty(sourceProp) !== isOptionalProperty(targetProp)) { return Ternary.False; } - return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); } + return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp)); } function compareSignatures(source: Signature, target: Signature, compareReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 0b39063d5e3..b233d3575b3 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -5,7 +5,10 @@ module ts { // Ternary values are defined such that // x & y is False if either x or y is False. // x & y is Maybe if either x or y is Maybe, but neither x or y is False. - // x & y is True if x and y are both True. + // x & y is True if both x and y are True. + // x | y is False if both x and y are False. + // x | y is Maybe if either x or y is Maybe, but neither x or y is True. + // x | y is True if either x or y is True. export enum Ternary { False = 0, Maybe = 1, diff --git a/tests/baselines/reference/checkInfiniteExpansionTermination.js b/tests/baselines/reference/checkInfiniteExpansionTermination.js new file mode 100644 index 00000000000..ed52ea6b419 --- /dev/null +++ b/tests/baselines/reference/checkInfiniteExpansionTermination.js @@ -0,0 +1,25 @@ +//// [checkInfiniteExpansionTermination.ts] +// Regression test for #1002 +// Before fix this code would cause infinite loop + +interface IObservable { + n: IObservable; // Needed, must be T[] +} + +// Needed +interface ISubject extends IObservable { } + +interface Foo { x } +interface Bar { y } + +var values: IObservable; +var values2: ISubject; +values = values2; + + +//// [checkInfiniteExpansionTermination.js] +// Regression test for #1002 +// Before fix this code would cause infinite loop +var values; +var values2; +values = values2; diff --git a/tests/baselines/reference/checkInfiniteExpansionTermination.types b/tests/baselines/reference/checkInfiniteExpansionTermination.types new file mode 100644 index 00000000000..bd4858126dd --- /dev/null +++ b/tests/baselines/reference/checkInfiniteExpansionTermination.types @@ -0,0 +1,44 @@ +=== tests/cases/compiler/checkInfiniteExpansionTermination.ts === +// Regression test for #1002 +// Before fix this code would cause infinite loop + +interface IObservable { +>IObservable : IObservable +>T : T + + n: IObservable; // Needed, must be T[] +>n : IObservable +>IObservable : IObservable +>T : T +} + +// Needed +interface ISubject extends IObservable { } +>ISubject : ISubject +>T : T +>IObservable : IObservable +>T : T + +interface Foo { x } +>Foo : Foo +>x : any + +interface Bar { y } +>Bar : Bar +>y : any + +var values: IObservable; +>values : IObservable +>IObservable : IObservable +>Foo : Foo + +var values2: ISubject; +>values2 : ISubject +>ISubject : ISubject +>Bar : Bar + +values = values2; +>values = values2 : ISubject +>values : IObservable +>values2 : ISubject + diff --git a/tests/baselines/reference/checkInfiniteExpansionTermination2.js b/tests/baselines/reference/checkInfiniteExpansionTermination2.js new file mode 100644 index 00000000000..6175b34e522 --- /dev/null +++ b/tests/baselines/reference/checkInfiniteExpansionTermination2.js @@ -0,0 +1,27 @@ +//// [checkInfiniteExpansionTermination2.ts] +// Regression test for #1002 +// Before fix this code would cause infinite loop + +interface IObservable { + n: IObservable; +} +interface ISubject extends IObservable { } + +declare function combineLatest(x: IObservable[]): void; +declare function combineLatest(): void; + +function fn() { + var values: ISubject[] = []; + // Hang when using , but not + combineLatest(values); +} + + +//// [checkInfiniteExpansionTermination2.js] +// Regression test for #1002 +// Before fix this code would cause infinite loop +function fn() { + var values = []; + // Hang when using , but not + combineLatest(values); +} diff --git a/tests/baselines/reference/checkInfiniteExpansionTermination2.types b/tests/baselines/reference/checkInfiniteExpansionTermination2.types new file mode 100644 index 00000000000..fc81e1c9304 --- /dev/null +++ b/tests/baselines/reference/checkInfiniteExpansionTermination2.types @@ -0,0 +1,46 @@ +=== tests/cases/compiler/checkInfiniteExpansionTermination2.ts === +// Regression test for #1002 +// Before fix this code would cause infinite loop + +interface IObservable { +>IObservable : IObservable +>T : T + + n: IObservable; +>n : IObservable +>IObservable : IObservable +>T : T +} +interface ISubject extends IObservable { } +>ISubject : ISubject +>T : T +>IObservable : IObservable +>T : T + +declare function combineLatest(x: IObservable[]): void; +>combineLatest : { (x: IObservable[]): void; (): void; } +>TOther : TOther +>x : IObservable[] +>IObservable : IObservable +>TOther : TOther + +declare function combineLatest(): void; +>combineLatest : { (x: IObservable[]): void; (): void; } + +function fn() { +>fn : () => void +>T : T + + var values: ISubject[] = []; +>values : ISubject[] +>ISubject : ISubject +>[] : undefined[] + + // Hang when using , but not + combineLatest(values); +>combineLatest(values) : void +>combineLatest : { (x: IObservable[]): void; (): void; } +>T : T +>values : ISubject[] +} + diff --git a/tests/baselines/reference/typeComparisonCaching.errors.txt b/tests/baselines/reference/typeComparisonCaching.errors.txt new file mode 100644 index 00000000000..3cbedebb7d2 --- /dev/null +++ b/tests/baselines/reference/typeComparisonCaching.errors.txt @@ -0,0 +1,45 @@ +tests/cases/compiler/typeComparisonCaching.ts(26,1): error TS2323: Type 'B' is not assignable to type 'A'. + Types of property 's' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/compiler/typeComparisonCaching.ts(27,1): error TS2323: Type 'D' is not assignable to type 'C'. + Types of property 'q' are incompatible. + Type 'B' is not assignable to type 'A'. + + +==== tests/cases/compiler/typeComparisonCaching.ts (2 errors) ==== + // Check that we only cache results of type comparisons that are free of assumptions + + interface A { + p: C; + s: string; + } + + interface B { + p: D; + s: number; + } + + interface C { + q: A; + } + + interface D { + q: B; + } + + var a: A; + var b: B; + var c: C; + var d: D; + + a = b; + ~ +!!! error TS2323: Type 'B' is not assignable to type 'A'. +!!! error TS2323: Types of property 's' are incompatible. +!!! error TS2323: Type 'number' is not assignable to type 'string'. + c = d; // Should not be allowed + ~ +!!! error TS2323: Type 'D' is not assignable to type 'C'. +!!! error TS2323: Types of property 'q' are incompatible. +!!! error TS2323: Type 'B' is not assignable to type 'A'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeComparisonCaching.js b/tests/baselines/reference/typeComparisonCaching.js new file mode 100644 index 00000000000..7d5eb29d52d --- /dev/null +++ b/tests/baselines/reference/typeComparisonCaching.js @@ -0,0 +1,38 @@ +//// [typeComparisonCaching.ts] +// Check that we only cache results of type comparisons that are free of assumptions + +interface A { + p: C; + s: string; +} + +interface B { + p: D; + s: number; +} + +interface C { + q: A; +} + +interface D { + q: B; +} + +var a: A; +var b: B; +var c: C; +var d: D; + +a = b; +c = d; // Should not be allowed + + +//// [typeComparisonCaching.js] +// Check that we only cache results of type comparisons that are free of assumptions +var a; +var b; +var c; +var d; +a = b; +c = d; // Should not be allowed diff --git a/tests/cases/compiler/checkInfiniteExpansionTermination.ts b/tests/cases/compiler/checkInfiniteExpansionTermination.ts new file mode 100644 index 00000000000..8514ebce966 --- /dev/null +++ b/tests/cases/compiler/checkInfiniteExpansionTermination.ts @@ -0,0 +1,16 @@ +// Regression test for #1002 +// Before fix this code would cause infinite loop + +interface IObservable { + n: IObservable; // Needed, must be T[] +} + +// Needed +interface ISubject extends IObservable { } + +interface Foo { x } +interface Bar { y } + +var values: IObservable; +var values2: ISubject; +values = values2; diff --git a/tests/cases/compiler/checkInfiniteExpansionTermination2.ts b/tests/cases/compiler/checkInfiniteExpansionTermination2.ts new file mode 100644 index 00000000000..f30499ba540 --- /dev/null +++ b/tests/cases/compiler/checkInfiniteExpansionTermination2.ts @@ -0,0 +1,16 @@ +// Regression test for #1002 +// Before fix this code would cause infinite loop + +interface IObservable { + n: IObservable; +} +interface ISubject extends IObservable { } + +declare function combineLatest(x: IObservable[]): void; +declare function combineLatest(): void; + +function fn() { + var values: ISubject[] = []; + // Hang when using , but not + combineLatest(values); +} diff --git a/tests/cases/compiler/typeComparisonCaching.ts b/tests/cases/compiler/typeComparisonCaching.ts new file mode 100644 index 00000000000..b47d35c60b6 --- /dev/null +++ b/tests/cases/compiler/typeComparisonCaching.ts @@ -0,0 +1,27 @@ +// Check that we only cache results of type comparisons that are free of assumptions + +interface A { + p: C; + s: string; +} + +interface B { + p: D; + s: number; +} + +interface C { + q: A; +} + +interface D { + q: B; +} + +var a: A; +var b: B; +var c: C; +var d: D; + +a = b; +c = d; // Should not be allowed