From 1da9630a34981601a11ecbafff5f1afaef136031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 26 Jul 2024 19:09:02 +0200 Subject: [PATCH] Bailout early from `isFunctionObjectType` for evolving arrays (#58049) Co-authored-by: Jake Bailey <5341706+jakebailey@users.noreply.github.com> --- src/compiler/checker.ts | 3 + ...ontainmentEvolvingArrayNoCrash1.errors.txt | 25 +++++++ ...inContainmentEvolvingArrayNoCrash1.symbols | 36 ++++++++++ ...hainContainmentEvolvingArrayNoCrash1.types | 68 +++++++++++++++++++ ...alChainContainmentEvolvingArrayNoCrash1.ts | 18 +++++ 5 files changed, 150 insertions(+) create mode 100644 tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.errors.txt create mode 100644 tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.symbols create mode 100644 tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.types create mode 100644 tests/cases/compiler/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f05c9b40df..78cee25efc9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27381,6 +27381,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isFunctionObjectType(type: ObjectType): boolean { + if (getObjectFlags(type) & ObjectFlags.EvolvingArray) { + return false; + } // We do a quick check for a "bind" property before performing the more expensive subtype // check. This gives us a quicker out in the common case where an object type is not a function. const resolved = resolveStructuredTypeMembers(type); diff --git a/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.errors.txt b/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.errors.txt new file mode 100644 index 00000000000..d503ac8d760 --- /dev/null +++ b/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.errors.txt @@ -0,0 +1,25 @@ +narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts(1,5): error TS7034: Variable 'foo' implicitly has type 'any[]' in some locations where its type cannot be determined. +narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts(5,5): error TS7005: Variable 'foo' implicitly has an 'any[]' type. + + +==== narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts (2 errors) ==== + let foo = []; + ~~~ +!!! error TS7034: Variable 'foo' implicitly has type 'any[]' in some locations where its type cannot be determined. + + switch (foo?.length) { + case 1: + foo[0]; + ~~~ +!!! error TS7005: Variable 'foo' implicitly has an 'any[]' type. + } + + let bar = []; + + switch (bar?.length) { + case 1: { + bar.push("baz"); + const arr: string[] = bar; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.symbols b/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.symbols new file mode 100644 index 00000000000..d766eadf659 --- /dev/null +++ b/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.symbols @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts] //// + +=== narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts === +let foo = []; +>foo : Symbol(foo, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 0, 3)) + +switch (foo?.length) { +>foo?.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>foo : Symbol(foo, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 0, 3)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + case 1: + foo[0]; +>foo : Symbol(foo, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 0, 3)) +} + +let bar = []; +>bar : Symbol(bar, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 7, 3)) + +switch (bar?.length) { +>bar?.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>bar : Symbol(bar, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 7, 3)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + case 1: { + bar.push("baz"); +>bar.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>bar : Symbol(bar, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 7, 3)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) + + const arr: string[] = bar; +>arr : Symbol(arr, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 12, 9)) +>bar : Symbol(bar, Decl(narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts, 7, 3)) + } +} + diff --git a/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.types b/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.types new file mode 100644 index 00000000000..0a5d8998007 --- /dev/null +++ b/tests/baselines/reference/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.types @@ -0,0 +1,68 @@ +//// [tests/cases/compiler/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts] //// + +=== narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts === +let foo = []; +>foo : any[] +> : ^^^^^ +>[] : never[] +> : ^^^^^^^ + +switch (foo?.length) { +>foo?.length : number +> : ^^^^^^ +>foo : any[] +> : ^^^^^ +>length : number +> : ^^^^^^ + + case 1: +>1 : 1 +> : ^ + + foo[0]; +>foo[0] : any +> : ^^^ +>foo : any[] +> : ^^^^^ +>0 : 0 +> : ^ +} + +let bar = []; +>bar : any[] +> : ^^^^^ +>[] : never[] +> : ^^^^^^^ + +switch (bar?.length) { +>bar?.length : number +> : ^^^^^^ +>bar : any[] +> : ^^^^^ +>length : number +> : ^^^^^^ + + case 1: { +>1 : 1 +> : ^ + + bar.push("baz"); +>bar.push("baz") : number +> : ^^^^^^ +>bar.push : (...items: any[]) => number +> : ^^^^ ^^^^^^^^^^^^ +>bar : any[] +> : ^^^^^ +>push : (...items: any[]) => number +> : ^^^^ ^^^^^^^^^^^^ +>"baz" : "baz" +> : ^^^^^ + + const arr: string[] = bar; +>arr : string[] +> : ^^^^^^^^ +>bar : string[] +> : ^^^^^^^^ + } +} + diff --git a/tests/cases/compiler/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts b/tests/cases/compiler/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts new file mode 100644 index 00000000000..d20c1c1160f --- /dev/null +++ b/tests/cases/compiler/narrowSwitchOptionalChainContainmentEvolvingArrayNoCrash1.ts @@ -0,0 +1,18 @@ +// @strict: true +// @noEmit: true + +let foo = []; + +switch (foo?.length) { + case 1: + foo[0]; +} + +let bar = []; + +switch (bar?.length) { + case 1: { + bar.push("baz"); + const arr: string[] = bar; + } +}