Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip parent error when reporting excess property checks #55152

17 changes: 14 additions & 3 deletions src/compiler/checker.ts
Expand Up @@ -20354,6 +20354,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid
let lastSkippedInfo: [Type, Type] | undefined;
let incompatibleStack: DiagnosticAndArguments[] | undefined;
let skipParentCounter = 0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This currently never goes higher than 1, but if we ever had the notion of an EPC->EPC nested error, that would be how it could happen. Open to changing it to a boolean if wanted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be captured in captureErrorCalculationState and reset in resetErrorInfo so it's set/unset when a speculative relationship elaboration pyramid is discarded. AFAIK, you'd need to do something like trigger EPC inside a conditional type or indexed access type where we end up using the constraint check rather than the normal check for validity for it to matter (and the bug would look something like us discarding elaboration layers for non-EPC errors). Definitely niche, but those functions are just there for capturing/restoring error pyramid state, so should also track this new variable.

Also, maybe a comment on how this differs from the nearby overrideNextErrorInfo number. (overrideNextErrorInfo skips the next N things in the pyramid, while when set this skips the N prior things in the pyramid.)


Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");

Expand Down Expand Up @@ -20544,7 +20545,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
Debug.assert(!!errorNode);
if (incompatibleStack) reportIncompatibleStack();
if (message.elidedInCompatabilityPyramid) return;
errorInfo = chainDiagnosticMessages(errorInfo, message, ...args);
if (skipParentCounter === 0) {
errorInfo = chainDiagnosticMessages(errorInfo, message, ...args);
}
else {
skipParentCounter--;
}
}

function reportParentSkippedError(message: DiagnosticMessage, ...args: DiagnosticArguments): void {
reportError(message, ...args);
skipParentCounter++;
}

function associateRelatedInfo(info: DiagnosticRelatedInformation) {
Expand Down Expand Up @@ -20941,11 +20952,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
if (suggestion !== undefined) {
reportError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2,
reportParentSkippedError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2,
symbolToString(prop), typeToString(errorTarget), suggestion);
}
else {
reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
reportParentSkippedError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
symbolToString(prop), typeToString(errorTarget));
}
}
Expand Down
6 changes: 2 additions & 4 deletions tests/baselines/reference/arrayCast.errors.txt
@@ -1,6 +1,5 @@
arrayCast.ts(3,23): error TS2352: Conversion of type '{ foo: string; }[]' to type '{ id: number; }[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Type '{ foo: string; }' is not comparable to type '{ id: number; }'.
Object literal may only specify known properties, and 'foo' does not exist in type '{ id: number; }'.
Object literal may only specify known properties, and 'foo' does not exist in type '{ id: number; }'.


==== arrayCast.ts (1 errors) ====
Expand All @@ -9,8 +8,7 @@ arrayCast.ts(3,23): error TS2352: Conversion of type '{ foo: string; }[]' to typ
<{ id: number; }[]>[{ foo: "s" }];
~~~
!!! error TS2352: Conversion of type '{ foo: string; }[]' to type '{ id: number; }[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
!!! error TS2352: Type '{ foo: string; }' is not comparable to type '{ id: number; }'.
!!! error TS2352: Object literal may only specify known properties, and 'foo' does not exist in type '{ id: number; }'.
!!! error TS2352: Object literal may only specify known properties, and 'foo' does not exist in type '{ id: number; }'.
Comment on lines -13 to +11
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error should never have been issued in the first place. It seems like a bug in our element-wise elaboration logic. Notice how in the following example one of these is has a missing property error and the other is an excess property error:

let okay = { foo: "" } as { id: 123 };
//         ~~~~~~~~~~~~~~~~~~~~~~~~~~
// Conversion of type '{ foo: string; }' to type '{ id: 123; }' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
//   Property 'id' is missing in type '{ foo: string; }' but required in type '{ id: 123; }'.

let waat = [{ foo: "" }] as { id: 123 }[];
//            ~~~
// Conversion of type '{ foo: string; }[]' to type '{ id: 123; }[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
//   Type '{ foo: string; }' is not comparable to type '{ id: 123; }'.
//     Object literal may only specify known properties, and 'foo' does not exist in type '{ id: 123; }'.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened up #55167

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wouldn’t ever expect an EPC error on a type assertion.


// Should succeed, as the {} element causes the type of the array to be {}[]
<{ id: number; }[]>[{ foo: "s" }, {}];
24 changes: 8 additions & 16 deletions tests/baselines/reference/arrayLiteralTypeInference.errors.txt
@@ -1,11 +1,7 @@
arrayLiteralTypeInference.ts(14,14): error TS2322: Type '{ id: number; trueness: false; }' is not assignable to type 'Action'.
Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
arrayLiteralTypeInference.ts(15,14): error TS2322: Type '{ id: number; name: string; }' is not assignable to type 'Action'.
Object literal may only specify known properties, and 'name' does not exist in type 'Action'.
arrayLiteralTypeInference.ts(31,18): error TS2322: Type '{ id: number; trueness: false; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
arrayLiteralTypeInference.ts(32,18): error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
arrayLiteralTypeInference.ts(14,14): error TS2353: Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
arrayLiteralTypeInference.ts(15,14): error TS2353: Object literal may only specify known properties, and 'name' does not exist in type 'Action'.
arrayLiteralTypeInference.ts(31,18): error TS2353: Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
arrayLiteralTypeInference.ts(32,18): error TS2353: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.


==== arrayLiteralTypeInference.ts (4 errors) ====
Expand All @@ -24,12 +20,10 @@ arrayLiteralTypeInference.ts(32,18): error TS2322: Type '{ id: number; name: str
var x1: Action[] = [
{ id: 2, trueness: false },
~~~~~~~~
!!! error TS2322: Type '{ id: number; trueness: false; }' is not assignable to type 'Action'.
!!! error TS2322: Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
!!! error TS2353: Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
{ id: 3, name: "three" }
~~~~
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type 'Action'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type 'Action'.
!!! error TS2353: Object literal may only specify known properties, and 'name' does not exist in type 'Action'.
]

var x2: Action[] = [
Expand All @@ -47,12 +41,10 @@ arrayLiteralTypeInference.ts(32,18): error TS2322: Type '{ id: number; name: str
[
{ id: 2, trueness: false },
~~~~~~~~
!!! error TS2322: Type '{ id: number; trueness: false; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
{ id: 3, name: "three" }
~~~~
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
]

var z2: { id: number }[] =
Expand Down
12 changes: 4 additions & 8 deletions tests/baselines/reference/arrayLiterals.errors.txt
@@ -1,7 +1,5 @@
arrayLiterals.ts(24,77): error TS2322: Type '{ a: string; b: number; c: string; }' is not assignable to type '{ a: string; b: number; }'.
Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
arrayLiterals.ts(24,101): error TS2322: Type '{ a: string; b: number; c: number; }' is not assignable to type '{ a: string; b: number; }'.
Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
arrayLiterals.ts(24,77): error TS2353: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
arrayLiterals.ts(24,101): error TS2353: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.


==== arrayLiterals.ts (2 errors) ====
Expand Down Expand Up @@ -30,12 +28,10 @@ arrayLiterals.ts(24,101): error TS2322: Type '{ a: string; b: number; c: number;
// Contextual type C with numeric index signature makes array literal of EveryType E of type BCT(E,C)[]
var context1: { [n: number]: { a: string; b: number; }; } = [{ a: '', b: 0, c: '' }, { a: "", b: 3, c: 0 }];
~
!!! error TS2322: Type '{ a: string; b: number; c: string; }' is not assignable to type '{ a: string; b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
!!! related TS6501 arrayLiterals.ts:24:17: The expected type comes from this index signature.
~
!!! error TS2322: Type '{ a: string; b: number; c: number; }' is not assignable to type '{ a: string; b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
!!! related TS6501 arrayLiterals.ts:24:17: The expected type comes from this index signature.
var context2 = [{ a: '', b: 0, c: '' }, { a: "", b: 3, c: 0 }];

Expand Down
18 changes: 6 additions & 12 deletions tests/baselines/reference/assignmentCompatBug2.errors.txt
@@ -1,9 +1,6 @@
assignmentCompatBug2.ts(1,27): error TS2322: Type '{ a: number; }' is not assignable to type '{ b: number; }'.
Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
assignmentCompatBug2.ts(3,8): error TS2322: Type '{ a: number; }' is not assignable to type '{ b: number; }'.
Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
assignmentCompatBug2.ts(5,13): error TS2322: Type '{ b: number; a: number; }' is not assignable to type '{ b: number; }'.
Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
assignmentCompatBug2.ts(1,27): error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
assignmentCompatBug2.ts(3,8): error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
assignmentCompatBug2.ts(5,13): error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
assignmentCompatBug2.ts(15,1): error TS2741: Property 'm' is missing in type '{ f: (n: number) => number; g: (s: string) => number; }' but required in type '{ f(n: number): number; g(s: string): number; m: number; n?: number; k?(a: any): any; }'.
assignmentCompatBug2.ts(20,1): error TS2741: Property 'g' is missing in type '{ f: (n: number) => number; m: number; }' but required in type '{ f(n: number): number; g(s: string): number; m: number; n?: number; k?(a: any): any; }'.
assignmentCompatBug2.ts(33,1): error TS2741: Property 'm' is missing in type '{ f: (n: number) => number; g: (s: string) => number; n: number; k: (a: any) => any; }' but required in type '{ f(n: number): number; g(s: string): number; m: number; n?: number; k?(a: any): any; }'.
Expand All @@ -12,18 +9,15 @@ assignmentCompatBug2.ts(33,1): error TS2741: Property 'm' is missing in type '{
==== assignmentCompatBug2.ts (6 errors) ====
var b2: { b: number;} = { a: 0 }; // error
~
!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.

b2 = { a: 0 }; // error
~
!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.

b2 = {b: 0, a: 0 };
~
!!! error TS2322: Type '{ b: number; a: number; }' is not assignable to type '{ b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ b: number; }'.

var b3: { f(n: number): number; g(s: string): number; m: number; n?: number; k?(a: any): any; };

Expand Down
6 changes: 2 additions & 4 deletions tests/baselines/reference/assignmentCompatBug5.errors.txt
@@ -1,5 +1,4 @@
assignmentCompatBug5.ts(2,8): error TS2345: Argument of type '{ b: number; }' is not assignable to parameter of type '{ a: number; }'.
Object literal may only specify known properties, and 'b' does not exist in type '{ a: number; }'.
assignmentCompatBug5.ts(2,8): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type '{ a: number; }'.
assignmentCompatBug5.ts(5,7): error TS2322: Type 'string' is not assignable to type 'number'.
assignmentCompatBug5.ts(5,12): error TS2322: Type 'string' is not assignable to type 'number'.
assignmentCompatBug5.ts(8,6): error TS2345: Argument of type '(s: string) => void' is not assignable to parameter of type '(n: number) => number'.
Expand All @@ -13,8 +12,7 @@ assignmentCompatBug5.ts(9,6): error TS2345: Argument of type '(n: number) => voi
function foo1(x: { a: number; }) { }
foo1({ b: 5 });
~
!!! error TS2345: Argument of type '{ b: number; }' is not assignable to parameter of type '{ a: number; }'.
!!! error TS2345: Object literal may only specify known properties, and 'b' does not exist in type '{ a: number; }'.
!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type '{ a: number; }'.

function foo2(x: number[]) { }
foo2(["s", "t"]);
Expand Down
12 changes: 4 additions & 8 deletions tests/baselines/reference/checkJsdocSatisfiesTag1.errors.txt
@@ -1,9 +1,7 @@
/a.js(21,44): error TS1360: Type '{ a: number; b: number; }' does not satisfy the expected type 'T1'.
Object literal may only specify known properties, and 'b' does not exist in type 'T1'.
/a.js(21,44): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'.
/a.js(22,17): error TS1360: Type '{}' does not satisfy the expected type 'T1'.
Property 'a' is missing in type '{}' but required in type 'T1'.
/a.js(31,49): error TS1360: Type '{ a: string; b: string; }' does not satisfy the expected type 'T4'.
Object literal may only specify known properties, and 'b' does not exist in type 'T4'.
/a.js(31,49): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T4'.


==== /a.js (3 errors) ====
Expand All @@ -29,8 +27,7 @@
const t1 = /** @satisfies {T1} */ ({ a: 1 });
const t2 = /** @satisfies {T1} */ ({ a: 1, b: 1 });
~
!!! error TS1360: Type '{ a: number; b: number; }' does not satisfy the expected type 'T1'.
!!! error TS1360: Object literal may only specify known properties, and 'b' does not exist in type 'T1'.
!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'.
const t3 = /** @satisfies {T1} */ ({});
~~~~~~~~~
!!! error TS1360: Type '{}' does not satisfy the expected type 'T1'.
Expand All @@ -46,6 +43,5 @@
const t7 = /** @satisfies {T4} */ ({ a: 'test' });
const t8 = /** @satisfies {T4} */ ({ a: 'test', b: 'test' });
~
!!! error TS1360: Type '{ a: string; b: string; }' does not satisfy the expected type 'T4'.
!!! error TS1360: Object literal may only specify known properties, and 'b' does not exist in type 'T4'.
!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T4'.

6 changes: 2 additions & 4 deletions tests/baselines/reference/checkJsdocSatisfiesTag10.errors.txt
@@ -1,5 +1,4 @@
/a.js(6,5): error TS1360: Type '{ a: number; b: string; x: number; }' does not satisfy the expected type 'Partial<Record<Keys, unknown>>'.
Object literal may only specify known properties, and 'x' does not exist in type 'Partial<Record<Keys, unknown>>'.
/a.js(6,5): error TS2353: Object literal may only specify known properties, and 'x' does not exist in type 'Partial<Record<Keys, unknown>>'.
/a.js(14,11): error TS2339: Property 'd' does not exist on type '{ a: number; b: string; x: number; }'.


Expand All @@ -11,8 +10,7 @@
b: "hello",
x: 8 // Should error, 'x' isn't in 'Keys'
~
!!! error TS1360: Type '{ a: number; b: string; x: number; }' does not satisfy the expected type 'Partial<Record<Keys, unknown>>'.
!!! error TS1360: Object literal may only specify known properties, and 'x' does not exist in type 'Partial<Record<Keys, unknown>>'.
!!! error TS2353: Object literal may only specify known properties, and 'x' does not exist in type 'Partial<Record<Keys, unknown>>'.
});

// Should be OK -- retain info that a is number and b is string
Expand Down
12 changes: 4 additions & 8 deletions tests/baselines/reference/checkJsdocSatisfiesTag12.errors.txt
@@ -1,7 +1,5 @@
/a.js(24,20): error TS1360: Type '{ a: number; b: number; }' does not satisfy the expected type 'T1'.
Object literal may only specify known properties, and 'b' does not exist in type 'T1'.
/a.js(44,25): error TS1360: Type '{ a: string; b: string; }' does not satisfy the expected type 'T2'.
Object literal may only specify known properties, and 'b' does not exist in type 'T2'.
/a.js(24,20): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'.
/a.js(44,25): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T2'.
/a.js(51,6): error TS1360: Type 'number' does not satisfy the expected type 'string'.


Expand Down Expand Up @@ -31,8 +29,7 @@
*/
const t2 = { a: 1, b: 1 };
~
!!! error TS1360: Type '{ a: number; b: number; }' does not satisfy the expected type 'T1'.
!!! error TS1360: Object literal may only specify known properties, and 'b' does not exist in type 'T1'.
!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'.

/**
* @satisfies {T1}
Expand All @@ -54,8 +51,7 @@
*/
const t6 = { a: 'test', b: 'test' };
~
!!! error TS1360: Type '{ a: string; b: string; }' does not satisfy the expected type 'T2'.
!!! error TS1360: Object literal may only specify known properties, and 'b' does not exist in type 'T2'.
!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T2'.

/**
* @satisfies {T3}
Expand Down