Skip to content

Commit

Permalink
Elaborate array and tuple relation errors
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-williams committed Apr 13, 2019
1 parent 4fee628 commit 7fa7c12
Show file tree
Hide file tree
Showing 12 changed files with 326 additions and 23 deletions.
49 changes: 44 additions & 5 deletions src/compiler/checker.ts
Expand Up @@ -12246,6 +12246,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.A_readonly_tuple_cannot_be_assigned_to_a_mutable_array_like_type);
}
return false;
}
return isArrayLikeType(target);
}
if (isTupleLikeType(target)) {
return isArrayLikeType(source);
}
if (isReadonlyArrayType(source) && isArrayType(target) && !isReadonlyArrayType(target)) {
if (reportErrors) {
reportError(Diagnostics.A_ReadonlyArray_cannot_be_assigned_to_an_Array_because_Array_s_can_be_mutated);
}
return false;
}
return true;
}

function isUnionOrIntersectionTypeWithoutNullableConstituents(type: Type): boolean {
if (!(type.flags & TypeFlags.UnionOrIntersection)) {
return false;
Expand Down Expand Up @@ -12418,6 +12452,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 @@ -13148,11 +13185,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
10 changes: 9 additions & 1 deletion src/compiler/diagnosticMessages.json
Expand Up @@ -2943,7 +2943,15 @@
"category": "Error",
"code": 4103
},

"A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.": {
"category": "Error",
"code": 4104
},
"A 'readonly' tuple cannot be assigned to a mutable array-like type.": {
"category": "Error",
"code": 4105
},

"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 TS4105: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(17,5): error TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
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 TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
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 TS4105: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
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 TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
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 TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
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]'.
A 'readonly' tuple cannot be assigned to a mutable array-like type.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(13,8): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
A 'readonly' tuple cannot be assigned to a mutable array-like type.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(16,9): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
A 'readonly' tuple cannot be assigned to a mutable array-like type.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(22,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(23,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(24,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.


==== 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: A 'readonly' tuple cannot be assigned to a mutable array-like type.

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: A 'readonly' tuple cannot be assigned to a mutable array-like type.

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: A 'readonly' tuple cannot be assigned to a mutable array-like type.

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: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
arryFn2(b);
~
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
arryFn2(c);
~
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.

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 7fa7c12

Please sign in to comment.