Skip to content

Commit

Permalink
Merge pull request #30916 from jack-williams/array-elaboration
Browse files Browse the repository at this point in the history
Elaborate array and tuple relation errors
  • Loading branch information
DanielRosenwasser committed Apr 15, 2019
2 parents 13d9f08 + 2ea91a0 commit 3dc78b6
Show file tree
Hide file tree
Showing 12 changed files with 322 additions and 23 deletions.
49 changes: 44 additions & 5 deletions src/compiler/checker.ts
Expand Up @@ -12241,6 +12241,40 @@ namespace ts {
}
}

/**
* Try and elaborate array and tuple errors. Returns false
* if we have found an elaboration, or we should ignore
* any other elaborations when relating the `source` and
* `target` types.
*
* @param source
* @param target
* @param reportErrors
*/
function tryElaborateArrayLikeErrors(source: Type, target: Type, reportErrors: boolean): boolean {
if (isTupleLikeType(source)) {
const sourceTuple: TupleType | undefined = (source as TupleTypeReference).target;
if (sourceTuple && sourceTuple.readonly && isArrayOrTupleLikeType(target) &&
(!isReadonlyArrayType(target) || isTupleType(target) && !target.target.readonly)) {
if (reportErrors) {
reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target));
}
return false;
}
return isArrayLikeType(target);
}
if (isTupleLikeType(target)) {
return isArrayLikeType(source);
}
if (isReadonlyArrayType(source) && isArrayType(target) && !isReadonlyArrayType(target)) {
if (reportErrors) {
reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target));
}
return false;
}
return true;
}

function isUnionOrIntersectionTypeWithoutNullableConstituents(type: Type): boolean {
if (!(type.flags & TypeFlags.UnionOrIntersection)) {
return false;
Expand Down Expand Up @@ -12413,6 +12447,9 @@ namespace ts {
if (!result && reportErrors) {
const maybeSuppress = suppressNextError;
suppressNextError = false;
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
tryElaborateArrayLikeErrors(source, target, reportErrors);
}
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) {
tryElaborateErrorsForPrimitivesAndObjects(source, target);
}
Expand Down Expand Up @@ -13143,11 +13180,13 @@ namespace ts {
associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
}
}
else if (props.length > 5) { // arbitrary cutoff for too-long list form
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
}
else {
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
else if (tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ false)) {
if (props.length > 5) { // arbitrary cutoff for too-long list form
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
}
else {
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
}
}
}
return Ternary.False;
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/diagnosticMessages.json
Expand Up @@ -2947,7 +2947,11 @@
"category": "Error",
"code": 4103
},

"The type '{0}' is 'readonly' and cannot be assigned to the mutable type '{1}'.": {
"category": "Error",
"code": 4104
},

"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001
Expand Down
4 changes: 1 addition & 3 deletions tests/baselines/reference/iterableArrayPattern10.errors.txt
@@ -1,5 +1,4 @@
tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts(17,5): error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.
Type 'FooIterator' is missing the following properties from type '[any, any]': 0, 1, length, pop, and 26 more.


==== tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts (1 errors) ====
Expand All @@ -21,5 +20,4 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts(17,5): error
function fun([a, b]) { }
fun(new FooIterator);
~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.
!!! error TS2345: Type 'FooIterator' is missing the following properties from type '[any, any]': 0, 1, length, pop, and 26 more.
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.
4 changes: 1 addition & 3 deletions tests/baselines/reference/iterableArrayPattern13.errors.txt
@@ -1,5 +1,4 @@
tests/cases/conformance/es6/destructuring/iterableArrayPattern13.ts(17,5): error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, ...any[]]'.
Type 'FooIterator' is missing the following properties from type '[any, ...any[]]': 0, length, pop, push, and 25 more.


==== tests/cases/conformance/es6/destructuring/iterableArrayPattern13.ts (1 errors) ====
Expand All @@ -21,5 +20,4 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern13.ts(17,5): error
function fun([a, ...b]) { }
fun(new FooIterator);
~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, ...any[]]'.
!!! error TS2345: Type 'FooIterator' is missing the following properties from type '[any, ...any[]]': 0, length, pop, push, and 25 more.
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, ...any[]]'.
2 changes: 0 additions & 2 deletions tests/baselines/reference/iterableArrayPattern16.errors.txt
@@ -1,5 +1,4 @@
tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts(2,5): error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[Bar, Bar]'.
Type 'FooIterator' is missing the following properties from type '[Bar, Bar]': 0, 1, length, pop, and 26 more.
tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts(2,12): error TS2449: Class 'FooIteratorIterator' used before its declaration.


Expand All @@ -8,7 +7,6 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts(2,12): error
fun(...new FooIteratorIterator);
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[Bar, Bar]'.
!!! error TS2345: Type 'FooIterator' is missing the following properties from type '[Bar, Bar]': 0, 1, length, pop, and 26 more.
~~~~~~~~~~~~~~~~~~~
!!! error TS2449: Class 'FooIteratorIterator' used before its declaration.
!!! related TS2728 tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts:18:7: 'FooIteratorIterator' is declared here.
Expand Down
4 changes: 1 addition & 3 deletions tests/baselines/reference/iterableArrayPattern26.errors.txt
@@ -1,10 +1,8 @@
tests/cases/conformance/es6/destructuring/iterableArrayPattern26.ts(2,21): error TS2345: Argument of type 'Map<string, number>' is not assignable to parameter of type '[string, number]'.
Type 'Map<string, number>' is missing the following properties from type '[string, number]': 0, 1, length, pop, and 22 more.


==== tests/cases/conformance/es6/destructuring/iterableArrayPattern26.ts (1 errors) ====
function takeFirstTwoEntries(...[[k1, v1], [k2, v2]]: [string, number][]) { }
takeFirstTwoEntries(new Map([["", 0], ["hello", 1]]));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type 'Map<string, number>' is not assignable to parameter of type '[string, number]'.
!!! error TS2345: Type 'Map<string, number>' is missing the following properties from type '[string, number]': 0, 1, length, pop, and 22 more.
!!! error TS2345: Argument of type 'Map<string, number>' is not assignable to parameter of type '[string, number]'.
12 changes: 6 additions & 6 deletions tests/baselines/reference/readonlyArraysAndTuples.errors.txt
Expand Up @@ -2,11 +2,11 @@ tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(9,12): error TS13
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(10,15): error TS1354: 'readonly' type modifier is only permitted on array and tuple literal types.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(11,12): error TS1354: 'readonly' type modifier is only permitted on array and tuple literal types.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(12,12): error TS1354: 'readonly' type modifier is only permitted on array and tuple literal types.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(15,5): error TS2740: Type 'readonly string[]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(17,5): error TS2740: Type 'readonly [string, string]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(15,5): error TS4104: The type 'readonly string[]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(17,5): error TS4104: The type 'readonly [string, string]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(21,5): error TS2739: Type 'string[]' is missing the following properties from type '[string, string]': 0, 1
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(22,5): error TS2740: Type 'readonly string[]' is missing the following properties from type '[string, string]': 0, 1, pop, push, and 5 more.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(23,5): error TS2740: Type 'readonly [string, string]' is missing the following properties from type '[string, string]': pop, push, reverse, shift, and 3 more.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(23,5): error TS4104: The type 'readonly [string, string]' is 'readonly' and cannot be assigned to the mutable type '[string, string]'.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(24,5): error TS2739: Type 'string[]' is missing the following properties from type 'readonly [string, string]': 0, 1
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(25,5): error TS2739: Type 'readonly string[]' is missing the following properties from type 'readonly [string, string]': 0, 1

Expand Down Expand Up @@ -36,11 +36,11 @@ tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(25,5): error TS27
function f1(ma: string[], ra: readonly string[], mt: [string, string], rt: readonly [string, string]) {
ma = ra; // Error
~~
!!! error TS2740: Type 'readonly string[]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
!!! error TS4104: The type 'readonly string[]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
ma = mt;
ma = rt; // Error
~~
!!! error TS2740: Type 'readonly [string, string]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
!!! error TS4104: The type 'readonly [string, string]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
ra = ma;
ra = mt;
ra = rt;
Expand All @@ -52,7 +52,7 @@ tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(25,5): error TS27
!!! error TS2740: Type 'readonly string[]' is missing the following properties from type '[string, string]': 0, 1, pop, push, and 5 more.
mt = rt; // Error
~~
!!! error TS2740: Type 'readonly [string, string]' is missing the following properties from type '[string, string]': pop, push, reverse, shift, and 3 more.
!!! error TS4104: The type 'readonly [string, string]' is 'readonly' and cannot be assigned to the mutable type '[string, string]'.
rt = ma; // Error
~~
!!! error TS2739: Type 'string[]' is missing the following properties from type 'readonly [string, string]': 0, 1
Expand Down
@@ -0,0 +1,58 @@
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(10,20): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type '[number, number]'.
The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type '[number, number]'.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(13,8): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(16,9): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(22,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(23,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(24,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.


==== tests/cases/compiler/readonlyTupleAndArrayElaboration.ts (6 errors) ====
// @strict
// #Repro from #30839

let point = [3, 4] as const;

function distanceFromOrigin([x, y]: [number, number]) {
return Math.sqrt(x ** 2 + y ** 2);
}

distanceFromOrigin(point);
~~~~~
!!! error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type '[number, number]'.
!!! error TS2345: The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type '[number, number]'.

declare function arryFn(x: number[]): void;
arryFn(point);
~~~~~
!!! error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.

declare function arryFn2(x: Array<number>): void;
arryFn2(point);
~~~~~
!!! error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.

declare const a: readonly number[];
declare const b: Readonly<number[]>;
declare const c: ReadonlyArray<number>;

arryFn2(a);
~
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
arryFn2(b);
~
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
arryFn2(c);
~
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.

41 changes: 41 additions & 0 deletions tests/baselines/reference/readonlyTupleAndArrayElaboration.js
@@ -0,0 +1,41 @@
//// [readonlyTupleAndArrayElaboration.ts]
// @strict
// #Repro from #30839

let point = [3, 4] as const;

function distanceFromOrigin([x, y]: [number, number]) {
return Math.sqrt(x ** 2 + y ** 2);
}

distanceFromOrigin(point);

declare function arryFn(x: number[]): void;
arryFn(point);

declare function arryFn2(x: Array<number>): void;
arryFn2(point);

declare const a: readonly number[];
declare const b: Readonly<number[]>;
declare const c: ReadonlyArray<number>;

arryFn2(a);
arryFn2(b);
arryFn2(c);


//// [readonlyTupleAndArrayElaboration.js]
// @strict
// #Repro from #30839
var point = [3, 4];
function distanceFromOrigin(_a) {
var x = _a[0], y = _a[1];
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
}
distanceFromOrigin(point);
arryFn(point);
arryFn2(point);
arryFn2(a);
arryFn2(b);
arryFn2(c);

0 comments on commit 3dc78b6

Please sign in to comment.