From 53a3d24b95c33952dfeef7668c688fa717aa1fb1 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:23:54 -0700 Subject: [PATCH 1/7] Fix fallthrough and default in new switch-true narrowing (#55991) --- src/compiler/checker.ts | 36 +- ...rrowByClauseExpressionInSwitchTrue.symbols | 144 -------- ...rowByClauseExpressionInSwitchTrue1.symbols | 144 ++++++++ ...rrowByClauseExpressionInSwitchTrue1.types} | 4 +- ...owByClauseExpressionInSwitchTrue10.symbols | 107 ++++++ ...rrowByClauseExpressionInSwitchTrue10.types | 111 ++++++ ...rowByClauseExpressionInSwitchTrue2.symbols | 49 +++ ...arrowByClauseExpressionInSwitchTrue2.types | 61 +++ ...ByClauseExpressionInSwitchTrue3.errors.txt | 32 ++ ...rowByClauseExpressionInSwitchTrue3.symbols | 60 +++ ...arrowByClauseExpressionInSwitchTrue3.types | 77 ++++ ...rowByClauseExpressionInSwitchTrue4.symbols | 21 ++ ...arrowByClauseExpressionInSwitchTrue4.types | 27 ++ ...rowByClauseExpressionInSwitchTrue5.symbols | 304 +++++++++++++++ ...arrowByClauseExpressionInSwitchTrue5.types | 348 ++++++++++++++++++ ...ByClauseExpressionInSwitchTrue6.errors.txt | 89 +++++ ...rowByClauseExpressionInSwitchTrue6.symbols | 198 ++++++++++ ...arrowByClauseExpressionInSwitchTrue6.types | 222 +++++++++++ ...ByClauseExpressionInSwitchTrue7.errors.txt | 90 +++++ ...rowByClauseExpressionInSwitchTrue7.symbols | 229 ++++++++++++ ...arrowByClauseExpressionInSwitchTrue7.types | 253 +++++++++++++ ...rowByClauseExpressionInSwitchTrue8.symbols | 57 +++ ...arrowByClauseExpressionInSwitchTrue8.types | 59 +++ ...rowByClauseExpressionInSwitchTrue9.symbols | 40 ++ ...arrowByClauseExpressionInSwitchTrue9.types | 40 ++ ... narrowByClauseExpressionInSwitchTrue1.ts} | 0 .../narrowByClauseExpressionInSwitchTrue10.ts | 56 +++ .../narrowByClauseExpressionInSwitchTrue2.ts | 29 ++ .../narrowByClauseExpressionInSwitchTrue3.ts | 22 ++ .../narrowByClauseExpressionInSwitchTrue4.ts | 12 + .../narrowByClauseExpressionInSwitchTrue5.ts | 133 +++++++ .../narrowByClauseExpressionInSwitchTrue6.ts | 78 ++++ .../narrowByClauseExpressionInSwitchTrue7.ts | 86 +++++ .../narrowByClauseExpressionInSwitchTrue8.ts | 32 ++ .../narrowByClauseExpressionInSwitchTrue9.ts | 20 + 35 files changed, 3119 insertions(+), 151 deletions(-) delete mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue1.symbols rename tests/baselines/reference/{narrowByClauseExpressionInSwitchTrue.types => narrowByClauseExpressionInSwitchTrue1.types} (90%) create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.errors.txt create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.errors.txt create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.errors.txt create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.types create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.symbols create mode 100644 tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.types rename tests/cases/compiler/{narrowByClauseExpressionInSwitchTrue.ts => narrowByClauseExpressionInSwitchTrue1.ts} (100%) create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue10.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue2.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue3.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue4.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue5.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue6.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue7.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue8.ts create mode 100644 tests/cases/compiler/narrowByClauseExpressionInSwitchTrue9.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 85700319fc371..2c9344679abd8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27456,11 +27456,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type = narrowTypeBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); } else if (expr.kind === SyntaxKind.TrueKeyword) { - const clause = flow.switchStatement.caseBlock.clauses.find((_, index) => index === flow.clauseStart); - const clauseExpression = clause && clause.kind === SyntaxKind.CaseClause ? clause.expression : undefined; - if (clauseExpression) { - type = narrowType(type, clauseExpression, /*assumeTrue*/ true); - } + type = narrowTypeBySwitchOnTrue(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); } else { if (strictNullChecks) { @@ -28075,6 +28071,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getUnionType(map(clauseWitnesses, text => text ? narrowTypeByTypeName(type, text) : neverType)); } + function narrowTypeBySwitchOnTrue(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type { + const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause); + const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); + + // First, narrow away all of the cases that preceded this set of cases. + for (let i = 0; i < clauseStart; i++) { + const clause = switchStatement.caseBlock.clauses[i]; + if (clause.kind === SyntaxKind.CaseClause) { + type = narrowType(type, clause.expression, /*assumeTrue*/ false); + } + } + + // If our current set has a default, then none the other cases were hit either. + // There's no point in narrowing by the the other cases in the set, since we can + // get here through other paths. + if (hasDefaultClause) { + for (let i = clauseEnd; i < switchStatement.caseBlock.clauses.length; i++) { + const clause = switchStatement.caseBlock.clauses[i]; + if (clause.kind === SyntaxKind.CaseClause) { + type = narrowType(type, clause.expression, /*assumeTrue*/ false); + } + } + return type; + } + + // Now, narrow based on the cases in this set. + const clauses = switchStatement.caseBlock.clauses.slice(clauseStart, clauseEnd); + return getUnionType(map(clauses, clause => clause.kind === SyntaxKind.CaseClause ? narrowType(type, clause.expression, /*assumeTrue*/ true) : neverType)); + } + function isMatchingConstructorReference(expr: Expression) { return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" || isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) && expr.argumentExpression.text === "constructor") && diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue.symbols deleted file mode 100644 index 6461b7c88b263..0000000000000 --- a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue.symbols +++ /dev/null @@ -1,144 +0,0 @@ -//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue.ts] //// - -=== narrowByClauseExpressionInSwitchTrue.ts === -// https://github.com/microsoft/TypeScript/issues/37178 - -type A = { type: "A" }; ->A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue.ts, 0, 0)) ->type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 10)) - -type B = { type: "B" }; ->B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 23)) ->type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 10)) - -type AorB = A | B; ->AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 23)) ->A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue.ts, 0, 0)) ->B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 23)) - -const isA = (x: AorB): x is A => x.type === "A"; ->isA : Symbol(isA, Decl(narrowByClauseExpressionInSwitchTrue.ts, 6, 5)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 6, 13)) ->AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 23)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 6, 13)) ->A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue.ts, 0, 0)) ->x.type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 10)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 6, 13)) ->type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 10)) - -const isB = (x: AorB): x is B => x.type === "B"; ->isB : Symbol(isB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 7, 5)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 7, 13)) ->AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 23)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 7, 13)) ->B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 23)) ->x.type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 10)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 7, 13)) ->type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 10)) - -function test1(x: AorB) { ->test1 : Symbol(test1, Decl(narrowByClauseExpressionInSwitchTrue.ts, 7, 48)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 9, 15)) ->AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 23)) - - switch (true) { - case isA(x): ->isA : Symbol(isA, Decl(narrowByClauseExpressionInSwitchTrue.ts, 6, 5)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 9, 15)) - - x; ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 9, 15)) - - break; - case isB(x): ->isB : Symbol(isB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 7, 5)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 9, 15)) - - x; ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 9, 15)) - - break; - } -} - -function test2(x: AorB) { ->test2 : Symbol(test2, Decl(narrowByClauseExpressionInSwitchTrue.ts, 18, 1)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 20, 15)) ->AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 3, 23)) - - switch (true) { - case isA(x): ->isA : Symbol(isA, Decl(narrowByClauseExpressionInSwitchTrue.ts, 6, 5)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 20, 15)) - - x; ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 20, 15)) - - // fallthrough - case isB(x): ->isB : Symbol(isB, Decl(narrowByClauseExpressionInSwitchTrue.ts, 7, 5)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 20, 15)) - - x; ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 20, 15)) - - break; - } -} - -let x: string | undefined; ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 31, 3)) - -switch (true) { - case typeof x !== "undefined": ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 31, 3)) - - x.trim(); ->x.trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 31, 3)) ->trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) -} - -type SomeType = { type: "SomeType" }; ->SomeType : Symbol(SomeType, Decl(narrowByClauseExpressionInSwitchTrue.ts, 36, 1)) ->type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue.ts, 38, 17)) - -declare function isSomeType(x: unknown): x is SomeType; ->isSomeType : Symbol(isSomeType, Decl(narrowByClauseExpressionInSwitchTrue.ts, 38, 37)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 39, 28)) ->x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue.ts, 39, 28)) ->SomeType : Symbol(SomeType, Decl(narrowByClauseExpressionInSwitchTrue.ts, 36, 1)) - -function processInput(input: string | RegExp | SomeType) { ->processInput : Symbol(processInput, Decl(narrowByClauseExpressionInSwitchTrue.ts, 39, 55)) ->input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue.ts, 41, 22)) ->RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->SomeType : Symbol(SomeType, Decl(narrowByClauseExpressionInSwitchTrue.ts, 36, 1)) - - switch (true) { - case typeof input === "string": ->input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue.ts, 41, 22)) - - input; ->input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue.ts, 41, 22)) - - break; - case input instanceof RegExp: ->input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue.ts, 41, 22)) ->RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) - - input; ->input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue.ts, 41, 22)) - - break; - case isSomeType(input): ->isSomeType : Symbol(isSomeType, Decl(narrowByClauseExpressionInSwitchTrue.ts, 38, 37)) ->input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue.ts, 41, 22)) - - input; ->input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue.ts, 41, 22)) - - break; - } -} - diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue1.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue1.symbols new file mode 100644 index 0000000000000..3892a6c7fddf4 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue1.symbols @@ -0,0 +1,144 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue1.ts] //// + +=== narrowByClauseExpressionInSwitchTrue1.ts === +// https://github.com/microsoft/TypeScript/issues/37178 + +type A = { type: "A" }; +>A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 0, 0)) +>type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 10)) + +type B = { type: "B" }; +>B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 23)) +>type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 10)) + +type AorB = A | B; +>AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 23)) +>A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 0, 0)) +>B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 23)) + +const isA = (x: AorB): x is A => x.type === "A"; +>isA : Symbol(isA, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 6, 5)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 6, 13)) +>AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 23)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 6, 13)) +>A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 0, 0)) +>x.type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 10)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 6, 13)) +>type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 10)) + +const isB = (x: AorB): x is B => x.type === "B"; +>isB : Symbol(isB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 7, 5)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 7, 13)) +>AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 23)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 7, 13)) +>B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 23)) +>x.type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 10)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 7, 13)) +>type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 10)) + +function test1(x: AorB) { +>test1 : Symbol(test1, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 7, 48)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 9, 15)) +>AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 23)) + + switch (true) { + case isA(x): +>isA : Symbol(isA, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 6, 5)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 9, 15)) + + x; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 9, 15)) + + break; + case isB(x): +>isB : Symbol(isB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 7, 5)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 9, 15)) + + x; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 9, 15)) + + break; + } +} + +function test2(x: AorB) { +>test2 : Symbol(test2, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 18, 1)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 20, 15)) +>AorB : Symbol(AorB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 3, 23)) + + switch (true) { + case isA(x): +>isA : Symbol(isA, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 6, 5)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 20, 15)) + + x; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 20, 15)) + + // fallthrough + case isB(x): +>isB : Symbol(isB, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 7, 5)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 20, 15)) + + x; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 20, 15)) + + break; + } +} + +let x: string | undefined; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 31, 3)) + +switch (true) { + case typeof x !== "undefined": +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 31, 3)) + + x.trim(); +>x.trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 31, 3)) +>trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) +} + +type SomeType = { type: "SomeType" }; +>SomeType : Symbol(SomeType, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 36, 1)) +>type : Symbol(type, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 38, 17)) + +declare function isSomeType(x: unknown): x is SomeType; +>isSomeType : Symbol(isSomeType, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 38, 37)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 39, 28)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 39, 28)) +>SomeType : Symbol(SomeType, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 36, 1)) + +function processInput(input: string | RegExp | SomeType) { +>processInput : Symbol(processInput, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 39, 55)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 41, 22)) +>RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>SomeType : Symbol(SomeType, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 36, 1)) + + switch (true) { + case typeof input === "string": +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 41, 22)) + + input; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 41, 22)) + + break; + case input instanceof RegExp: +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 41, 22)) +>RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + input; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 41, 22)) + + break; + case isSomeType(input): +>isSomeType : Symbol(isSomeType, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 38, 37)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 41, 22)) + + input; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue1.ts, 41, 22)) + + break; + } +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue1.types similarity index 90% rename from tests/baselines/reference/narrowByClauseExpressionInSwitchTrue.types rename to tests/baselines/reference/narrowByClauseExpressionInSwitchTrue1.types index f8a1d9bc87e42..fa20aae9246ba 100644 --- a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue.types +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue1.types @@ -1,6 +1,6 @@ -//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue.ts] //// +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue1.ts] //// -=== narrowByClauseExpressionInSwitchTrue.ts === +=== narrowByClauseExpressionInSwitchTrue1.ts === // https://github.com/microsoft/TypeScript/issues/37178 type A = { type: "A" }; diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.symbols new file mode 100644 index 0000000000000..2abb5fc5d41ec --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.symbols @@ -0,0 +1,107 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue10.ts] //// + +=== narrowByClauseExpressionInSwitchTrue10.ts === +function foo(cond1: boolean, cond2: boolean) { +>foo : Symbol(foo, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 0)) +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 13)) +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 28)) + + switch (true) { + case cond1 || cond2: +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 13)) +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 28)) + + cond1; // boolean +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 13)) + + // ^? + cond2; // boolean +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 28)) + + // ^? + break; + + case cond2: +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 28)) + + cond1; // false +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 13)) + + // ^? + cond2;; // never +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 28)) + + // ^? + break; + + default: + cond1; // false +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 13)) + + // ^? + cond2; // false +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 28)) + + // ^? + break; + } + + cond1; // boolean +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 13)) + + // ^? + cond2; // boolean +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 0, 28)) + + // ^? +} + +function blah(cond1: boolean, cond2: boolean) { +>blah : Symbol(blah, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 28, 1)) +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 14)) +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 29)) + + if (cond1 || cond2) { +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 14)) +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 29)) + + cond1; // boolean +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 14)) + + // ^? + cond2; // boolean +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 29)) + + // ^? + } else if (cond2) { +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 29)) + + cond1; // false +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 14)) + + // ^? + cond2; // never +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 29)) + + // ^? + } else { + cond1; // false +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 14)) + + // ^? + cond2; // false +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 29)) + + // ^? + } + + cond1; // boolean +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 14)) + + // ^? + cond2; // boolean +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue10.ts, 30, 29)) + + // ^? +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.types new file mode 100644 index 0000000000000..d6e8cedfdc64e --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue10.types @@ -0,0 +1,111 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue10.ts] //// + +=== narrowByClauseExpressionInSwitchTrue10.ts === +function foo(cond1: boolean, cond2: boolean) { +>foo : (cond1: boolean, cond2: boolean) => void +>cond1 : boolean +>cond2 : boolean + + switch (true) { +>true : true + + case cond1 || cond2: +>cond1 || cond2 : boolean +>cond1 : boolean +>cond2 : boolean + + cond1; // boolean +>cond1 : boolean + + // ^? + cond2; // boolean +>cond2 : boolean + + // ^? + break; + + case cond2: +>cond2 : boolean + + cond1; // false +>cond1 : false + + // ^? + cond2;; // never +>cond2 : never + + // ^? + break; + + default: + cond1; // false +>cond1 : false + + // ^? + cond2; // false +>cond2 : false + + // ^? + break; + } + + cond1; // boolean +>cond1 : boolean + + // ^? + cond2; // boolean +>cond2 : boolean + + // ^? +} + +function blah(cond1: boolean, cond2: boolean) { +>blah : (cond1: boolean, cond2: boolean) => void +>cond1 : boolean +>cond2 : boolean + + if (cond1 || cond2) { +>cond1 || cond2 : boolean +>cond1 : boolean +>cond2 : boolean + + cond1; // boolean +>cond1 : boolean + + // ^? + cond2; // boolean +>cond2 : boolean + + // ^? + } else if (cond2) { +>cond2 : false + + cond1; // false +>cond1 : false + + // ^? + cond2; // never +>cond2 : never + + // ^? + } else { + cond1; // false +>cond1 : false + + // ^? + cond2; // false +>cond2 : false + + // ^? + } + + cond1; // boolean +>cond1 : boolean + + // ^? + cond2; // boolean +>cond2 : boolean + + // ^? +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.symbols new file mode 100644 index 0000000000000..8ce5e2928f487 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.symbols @@ -0,0 +1,49 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue2.ts] //// + +=== narrowByClauseExpressionInSwitchTrue2.ts === +// https://github.com/microsoft/TypeScript/issues/55986 + +declare const f: 'a' | 'b' | 'c'; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + +switch(true) { + case f === 'a': +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + + case f === 'b': +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + + f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + + break + default: + f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) +} + +f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + +switch(true) { + case f === 'a': +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + + f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + + case f === 'b': +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + + f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + + break + default: + f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) +} + +f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue2.ts, 2, 13)) + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.types new file mode 100644 index 0000000000000..d1637eb248fd5 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue2.types @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue2.ts] //// + +=== narrowByClauseExpressionInSwitchTrue2.ts === +// https://github.com/microsoft/TypeScript/issues/55986 + +declare const f: 'a' | 'b' | 'c'; +>f : "a" | "b" | "c" + +switch(true) { +>true : true + + case f === 'a': +>f === 'a' : boolean +>f : "a" | "b" | "c" +>'a' : "a" + + case f === 'b': +>f === 'b' : boolean +>f : "a" | "b" | "c" +>'b' : "b" + + f; +>f : "a" | "b" + + break + default: + f; +>f : "c" +} + +f; +>f : "a" | "b" | "c" + +switch(true) { +>true : true + + case f === 'a': +>f === 'a' : boolean +>f : "a" | "b" | "c" +>'a' : "a" + + f; +>f : "a" + + case f === 'b': +>f === 'b' : boolean +>f : "a" | "b" | "c" +>'b' : "b" + + f; +>f : "a" | "b" + + break + default: + f; +>f : "c" +} + +f; +>f : "a" | "b" | "c" + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.errors.txt b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.errors.txt new file mode 100644 index 0000000000000..cec1802a21fcf --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.errors.txt @@ -0,0 +1,32 @@ +narrowByClauseExpressionInSwitchTrue3.ts(12,9): error TS2367: This comparison appears to be unintentional because the types '"square"' and '"circle"' have no overlap. +narrowByClauseExpressionInSwitchTrue3.ts(13,32): error TS2339: Property 'radius' does not exist on type 'never'. +narrowByClauseExpressionInSwitchTrue3.ts(15,14): error TS2367: This comparison appears to be unintentional because the types '"square"' and '"circle"' have no overlap. + + +==== narrowByClauseExpressionInSwitchTrue3.ts (3 errors) ==== + type Shape = + | { kind: "circle", radius: number } + | { kind: "square", sideLength: number } + + function wat(shape: Shape) { + switch (true) { + case shape.kind === "circle": + return Math.PI * shape.radius ** 2; + case shape.kind === "circle": // should error + } + + if (shape.kind === "circle") { + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types '"square"' and '"circle"' have no overlap. + return Math.PI * shape.radius ** 2; + ~~~~~~ +!!! error TS2339: Property 'radius' does not exist on type 'never'. + } + else if (shape.kind === "circle") { + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types '"square"' and '"circle"' have no overlap. + // ~~~~ + // Property 'kind' does not exist on type 'never'. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.symbols new file mode 100644 index 0000000000000..b6811492524e1 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.symbols @@ -0,0 +1,60 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue3.ts] //// + +=== narrowByClauseExpressionInSwitchTrue3.ts === +type Shape = +>Shape : Symbol(Shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 0, 0)) + + | { kind: "circle", radius: number } +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 7)) +>radius : Symbol(radius, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 23)) + + | { kind: "square", sideLength: number } +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) +>sideLength : Symbol(sideLength, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 23)) + +function wat(shape: Shape) { +>wat : Symbol(wat, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 44)) +>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13)) +>Shape : Symbol(Shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 0, 0)) + + switch (true) { + case shape.kind === "circle": +>shape.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 7), Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) +>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 7), Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) + + return Math.PI * shape.radius ** 2; +>Math.PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --)) +>shape.radius : Symbol(radius, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 23)) +>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13)) +>radius : Symbol(radius, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 23)) + + case shape.kind === "circle": // should error +>shape.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 7), Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) +>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 7), Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) + } + + if (shape.kind === "circle") { +>shape.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) +>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) + + return Math.PI * shape.radius ** 2; +>Math.PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --)) +>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13)) + } + else if (shape.kind === "circle") { +>shape.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) +>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7)) + + // ~~~~ + // Property 'kind' does not exist on type 'never'. + } +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.types new file mode 100644 index 0000000000000..1fde85a02984d --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.types @@ -0,0 +1,77 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue3.ts] //// + +=== narrowByClauseExpressionInSwitchTrue3.ts === +type Shape = +>Shape : { kind: "circle"; radius: number; } | { kind: "square"; sideLength: number; } + + | { kind: "circle", radius: number } +>kind : "circle" +>radius : number + + | { kind: "square", sideLength: number } +>kind : "square" +>sideLength : number + +function wat(shape: Shape) { +>wat : (shape: Shape) => number | undefined +>shape : Shape + + switch (true) { +>true : true + + case shape.kind === "circle": +>shape.kind === "circle" : boolean +>shape.kind : "circle" | "square" +>shape : Shape +>kind : "circle" | "square" +>"circle" : "circle" + + return Math.PI * shape.radius ** 2; +>Math.PI * shape.radius ** 2 : number +>Math.PI : number +>Math : Math +>PI : number +>shape.radius ** 2 : number +>shape.radius : number +>shape : { kind: "circle"; radius: number; } +>radius : number +>2 : 2 + + case shape.kind === "circle": // should error +>shape.kind === "circle" : boolean +>shape.kind : "circle" | "square" +>shape : Shape +>kind : "circle" | "square" +>"circle" : "circle" + } + + if (shape.kind === "circle") { +>shape.kind === "circle" : boolean +>shape.kind : "square" +>shape : { kind: "square"; sideLength: number; } +>kind : "square" +>"circle" : "circle" + + return Math.PI * shape.radius ** 2; +>Math.PI * shape.radius ** 2 : number +>Math.PI : number +>Math : Math +>PI : number +>shape.radius ** 2 : number +>shape.radius : any +>shape : never +>radius : any +>2 : 2 + } + else if (shape.kind === "circle") { +>shape.kind === "circle" : boolean +>shape.kind : "square" +>shape : { kind: "square"; sideLength: number; } +>kind : "square" +>"circle" : "circle" + + // ~~~~ + // Property 'kind' does not exist on type 'never'. + } +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.symbols new file mode 100644 index 0000000000000..c505b1d47c975 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.symbols @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue4.ts] //// + +=== narrowByClauseExpressionInSwitchTrue4.ts === +declare const f: 'a' | 'b' | 'c'; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue4.ts, 0, 13)) + +switch (true) { + case f === "a": +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue4.ts, 0, 13)) + + default: + f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue4.ts, 0, 13)) + + case f === "b": +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue4.ts, 0, 13)) + + f; +>f : Symbol(f, Decl(narrowByClauseExpressionInSwitchTrue4.ts, 0, 13)) +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.types new file mode 100644 index 0000000000000..8dc6062a2b695 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue4.types @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue4.ts] //// + +=== narrowByClauseExpressionInSwitchTrue4.ts === +declare const f: 'a' | 'b' | 'c'; +>f : "a" | "b" | "c" + +switch (true) { +>true : true + + case f === "a": +>f === "a" : boolean +>f : "a" | "b" | "c" +>"a" : "a" + + default: + f; +>f : "a" | "c" + + case f === "b": +>f === "b" : boolean +>f : "a" | "b" | "c" +>"b" : "b" + + f; +>f : "a" | "b" | "c" +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.symbols new file mode 100644 index 0000000000000..3c890662516f5 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.symbols @@ -0,0 +1,304 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue5.ts] //// + +=== narrowByClauseExpressionInSwitchTrue5.ts === +type A = { kind: "A", value: number }; +>A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 0)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10)) +>value : Symbol(value, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 21)) + +type B = { kind: "B", name: string }; +>B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 38)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) +>name : Symbol(name, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 21)) + +type C = { kind: "C", cond: boolean }; +>C : Symbol(C, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 37)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10)) +>cond : Symbol(cond, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 21)) + +type D = { kind: "D", value: boolean }; +>D : Symbol(D, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 38)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10)) +>value : Symbol(value, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 21)) + +type E = { kind: "E", x: number, y: number }; +>E : Symbol(E, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 39)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 21)) +>y : Symbol(y, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 32)) + +type All = A | B | C | D | E; +>All : Symbol(All, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 45)) +>A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 0)) +>B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 38)) +>C : Symbol(C, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 37)) +>D : Symbol(D, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 38)) +>E : Symbol(E, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 39)) + +function fn1switch(input: All) { +>fn1switch : Symbol(fn1switch, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 6, 29)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) +>All : Symbol(All, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 45)) + + switch (true) { + case input.kind === "A": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + case input.kind === "B": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + if (input.kind === "A") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) + + return; + } + + input; // Should be B; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) + + // ^? + + // fallthrough + case input.kind === "C": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + input; // Should be B | C +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) + + // ^? + break; + default: + input; // Should be D | E +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) + + // ^? + } + + input; // Should not be A +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 8, 19)) + + // ^? +} + +function fn1ifelse(input: All) { +>fn1ifelse : Symbol(fn1ifelse, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 31, 1)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) +>All : Symbol(All, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 45)) + + if (input.kind === "A" || input.kind === "B") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + if (input.kind === "A") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) + + return; + } + + input; // Should be B; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) + + // ^? + } + if (input.kind === "C" || input.kind === "B") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + input; // Should be B | C +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) + + // ^? + } + else { + input; // Should be D | E +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) + + // ^? + } + + input; // Should not be A +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 33, 19)) + + // ^? +} + +function fn2switch(input: All) { +>fn2switch : Symbol(fn2switch, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 53, 1)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) +>All : Symbol(All, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 45)) + + switch (true) { + case input.kind === "A": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + case input.kind === "B": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + if (input.kind === "A") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) + + return; + } + + input; // Should be B; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) + + // ^? + + // fallthrough + case input.kind === "C": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + input; // Should be B | C +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) + + // ^? + break; + default: + input; // Should be D | E +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) + + // ^? + return; + } + + input; // Should be B | C +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 55, 19)) + + // ^? +} + +function fn2ifelse(input: All) { +>fn2ifelse : Symbol(fn2ifelse, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 79, 1)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) +>All : Symbol(All, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 45)) + + if (input.kind === "A" || input.kind === "B") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + if (input.kind === "A") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) + + return; + } + + input; // Should be B; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) + + // ^? + } + if (input.kind === "C" || input.kind === "B") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + input; // Should be B | C +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) + + // ^? + } + else { + input; // Should be D | E +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) + + // ^? + return; + } + + input; // Should be B | C +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 81, 19)) + + // ^? +} + +function fn3switch(input: All) { +>fn3switch : Symbol(fn3switch, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 102, 1)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) +>All : Symbol(All, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 45)) + + switch (true) { + case input.kind === "A": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + case input.kind === "B": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + if (input.kind === "A") { +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10)) + + return; + } + + input; // Should be B; +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) + + // ^? + + // fallthrough + default: + input; // Should be B | D | E +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) + + // ^? + break; + + case input.kind === "C": +>input.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 0, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 1, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 2, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 3, 10), Decl(narrowByClauseExpressionInSwitchTrue5.ts, 4, 10)) + + input; // Should be C +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) + + // ^? + break; + } + + input; // Should not be A +>input : Symbol(input, Decl(narrowByClauseExpressionInSwitchTrue5.ts, 104, 19)) + + // ^? +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.types new file mode 100644 index 0000000000000..d2b4c5c0780de --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue5.types @@ -0,0 +1,348 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue5.ts] //// + +=== narrowByClauseExpressionInSwitchTrue5.ts === +type A = { kind: "A", value: number }; +>A : { kind: "A"; value: number; } +>kind : "A" +>value : number + +type B = { kind: "B", name: string }; +>B : { kind: "B"; name: string; } +>kind : "B" +>name : string + +type C = { kind: "C", cond: boolean }; +>C : { kind: "C"; cond: boolean; } +>kind : "C" +>cond : boolean + +type D = { kind: "D", value: boolean }; +>D : { kind: "D"; value: boolean; } +>kind : "D" +>value : boolean + +type E = { kind: "E", x: number, y: number }; +>E : { kind: "E"; x: number; y: number; } +>kind : "E" +>x : number +>y : number + +type All = A | B | C | D | E; +>All : A | B | C | D | E + +function fn1switch(input: All) { +>fn1switch : (input: All) => void +>input : All + + switch (true) { +>true : true + + case input.kind === "A": +>input.kind === "A" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"A" : "A" + + case input.kind === "B": +>input.kind === "B" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"B" : "B" + + if (input.kind === "A") { +>input.kind === "A" : boolean +>input.kind : "A" | "B" +>input : A | B +>kind : "A" | "B" +>"A" : "A" + + return; + } + + input; // Should be B; +>input : B + + // ^? + + // fallthrough + case input.kind === "C": +>input.kind === "C" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"C" : "C" + + input; // Should be B | C +>input : B | C + + // ^? + break; + default: + input; // Should be D | E +>input : D | E + + // ^? + } + + input; // Should not be A +>input : B | C | D | E + + // ^? +} + +function fn1ifelse(input: All) { +>fn1ifelse : (input: All) => void +>input : All + + if (input.kind === "A" || input.kind === "B") { +>input.kind === "A" || input.kind === "B" : boolean +>input.kind === "A" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"A" : "A" +>input.kind === "B" : boolean +>input.kind : "B" | "C" | "D" | "E" +>input : B | C | D | E +>kind : "B" | "C" | "D" | "E" +>"B" : "B" + + if (input.kind === "A") { +>input.kind === "A" : boolean +>input.kind : "A" | "B" +>input : A | B +>kind : "A" | "B" +>"A" : "A" + + return; + } + + input; // Should be B; +>input : B + + // ^? + } + if (input.kind === "C" || input.kind === "B") { +>input.kind === "C" || input.kind === "B" : boolean +>input.kind === "C" : boolean +>input.kind : "B" | "C" | "D" | "E" +>input : B | C | D | E +>kind : "B" | "C" | "D" | "E" +>"C" : "C" +>input.kind === "B" : boolean +>input.kind : "B" | "D" | "E" +>input : B | D | E +>kind : "B" | "D" | "E" +>"B" : "B" + + input; // Should be B | C +>input : B | C + + // ^? + } + else { + input; // Should be D | E +>input : D | E + + // ^? + } + + input; // Should not be A +>input : B | C | D | E + + // ^? +} + +function fn2switch(input: All) { +>fn2switch : (input: All) => void +>input : All + + switch (true) { +>true : true + + case input.kind === "A": +>input.kind === "A" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"A" : "A" + + case input.kind === "B": +>input.kind === "B" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"B" : "B" + + if (input.kind === "A") { +>input.kind === "A" : boolean +>input.kind : "A" | "B" +>input : A | B +>kind : "A" | "B" +>"A" : "A" + + return; + } + + input; // Should be B; +>input : B + + // ^? + + // fallthrough + case input.kind === "C": +>input.kind === "C" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"C" : "C" + + input; // Should be B | C +>input : B | C + + // ^? + break; + default: + input; // Should be D | E +>input : D | E + + // ^? + return; + } + + input; // Should be B | C +>input : B | C + + // ^? +} + +function fn2ifelse(input: All) { +>fn2ifelse : (input: All) => void +>input : All + + if (input.kind === "A" || input.kind === "B") { +>input.kind === "A" || input.kind === "B" : boolean +>input.kind === "A" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"A" : "A" +>input.kind === "B" : boolean +>input.kind : "B" | "C" | "D" | "E" +>input : B | C | D | E +>kind : "B" | "C" | "D" | "E" +>"B" : "B" + + if (input.kind === "A") { +>input.kind === "A" : boolean +>input.kind : "A" | "B" +>input : A | B +>kind : "A" | "B" +>"A" : "A" + + return; + } + + input; // Should be B; +>input : B + + // ^? + } + if (input.kind === "C" || input.kind === "B") { +>input.kind === "C" || input.kind === "B" : boolean +>input.kind === "C" : boolean +>input.kind : "B" | "C" | "D" | "E" +>input : B | C | D | E +>kind : "B" | "C" | "D" | "E" +>"C" : "C" +>input.kind === "B" : boolean +>input.kind : "B" | "D" | "E" +>input : B | D | E +>kind : "B" | "D" | "E" +>"B" : "B" + + input; // Should be B | C +>input : B | C + + // ^? + } + else { + input; // Should be D | E +>input : D | E + + // ^? + return; + } + + input; // Should be B | C +>input : B | C + + // ^? +} + +function fn3switch(input: All) { +>fn3switch : (input: All) => void +>input : All + + switch (true) { +>true : true + + case input.kind === "A": +>input.kind === "A" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"A" : "A" + + case input.kind === "B": +>input.kind === "B" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"B" : "B" + + if (input.kind === "A") { +>input.kind === "A" : boolean +>input.kind : "A" | "B" +>input : A | B +>kind : "A" | "B" +>"A" : "A" + + return; + } + + input; // Should be B; +>input : B + + // ^? + + // fallthrough + default: + input; // Should be B | D | E +>input : B | D | E + + // ^? + break; + + case input.kind === "C": +>input.kind === "C" : boolean +>input.kind : "A" | "B" | "C" | "D" | "E" +>input : All +>kind : "A" | "B" | "C" | "D" | "E" +>"C" : "C" + + input; // Should be C +>input : C + + // ^? + break; + } + + input; // Should not be A +>input : B | C | D | E + + // ^? +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.errors.txt b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.errors.txt new file mode 100644 index 0000000000000..e33e6ac6fceab --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.errors.txt @@ -0,0 +1,89 @@ +narrowByClauseExpressionInSwitchTrue6.ts(70,15): error TS2339: Property 'bProps' does not exist on type 'A | B'. + Property 'bProps' does not exist on type 'A'. +narrowByClauseExpressionInSwitchTrue6.ts(73,15): error TS2339: Property 'cProps' does not exist on type 'MyType'. + Property 'cProps' does not exist on type 'A'. + + +==== narrowByClauseExpressionInSwitchTrue6.ts (2 errors) ==== + interface A { + kind: "a"; + aProps: string; + } + + interface B { + kind: "b"; + bProps: string; + } + + interface C { + kind: "c"; + cProps: string; + } + + + type MyType = A | B | C; + + function isA(x: MyType) { + switch (true) { + default: + const never: never = x; + case x.kind === "a": + x.aProps; + break; + case x.kind === "b": + x.bProps; + break; + case x.kind === "c": + x.cProps; + break; + } + + switch (true) { + default: + const never: never = x; + case x.kind === "a": { + x.aProps; + break; + } + case x.kind === "b": { + x.bProps; + break; + } + case x.kind === "c": { + x.cProps; + break; + } + } + + switch (true) { + default: + x.aProps; + break; + case x.kind === "b": + x.bProps; + break; + case x.kind === "c": + x.cProps; + break; + } + + switch (true) { + default: + const never: never = x; + case x.kind === "a": + x.aProps; + // fallthrough + case x.kind === "b": + x.bProps; + ~~~~~~ +!!! error TS2339: Property 'bProps' does not exist on type 'A | B'. +!!! error TS2339: Property 'bProps' does not exist on type 'A'. + // fallthrough + case x.kind === "c": + x.cProps; + ~~~~~~ +!!! error TS2339: Property 'cProps' does not exist on type 'MyType'. +!!! error TS2339: Property 'cProps' does not exist on type 'A'. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.symbols new file mode 100644 index 0000000000000..9ed6be6a7cf6c --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.symbols @@ -0,0 +1,198 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue6.ts] //// + +=== narrowByClauseExpressionInSwitchTrue6.ts === +interface A { +>A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 0)) + + kind: "a"; +>kind : Symbol(A.kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13)) + + aProps: string; +>aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) +} + +interface B { +>B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 3, 1)) + + kind: "b"; +>kind : Symbol(B.kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13)) + + bProps: string; +>bProps : Symbol(B.bProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 6, 14)) +} + +interface C { +>C : Symbol(C, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 8, 1)) + + kind: "c"; +>kind : Symbol(C.kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + cProps: string; +>cProps : Symbol(C.cProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 11, 14)) +} + + +type MyType = A | B | C; +>MyType : Symbol(MyType, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 13, 1)) +>A : Symbol(A, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 0)) +>B : Symbol(B, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 3, 1)) +>C : Symbol(C, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 8, 1)) + +function isA(x: MyType) { +>isA : Symbol(isA, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 16, 24)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>MyType : Symbol(MyType, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 13, 1)) + + switch (true) { + default: + const never: never = x; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 21, 17)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) + + case x.kind === "a": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.aProps; +>x.aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) + + break; + case x.kind === "b": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.bProps; +>x.bProps : Symbol(B.bProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 6, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>bProps : Symbol(B.bProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 6, 14)) + + break; + case x.kind === "c": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.cProps; +>x.cProps : Symbol(C.cProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 11, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>cProps : Symbol(C.cProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 11, 14)) + + break; + } + + switch (true) { + default: + const never: never = x; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 35, 17)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) + + case x.kind === "a": { +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.aProps; +>x.aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) + + break; + } + case x.kind === "b": { +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.bProps; +>x.bProps : Symbol(B.bProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 6, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>bProps : Symbol(B.bProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 6, 14)) + + break; + } + case x.kind === "c": { +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.cProps; +>x.cProps : Symbol(C.cProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 11, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>cProps : Symbol(C.cProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 11, 14)) + + break; + } + } + + switch (true) { + default: + x.aProps; +>x.aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) + + break; + case x.kind === "b": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.bProps; +>x.bProps : Symbol(B.bProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 6, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>bProps : Symbol(B.bProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 6, 14)) + + break; + case x.kind === "c": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.cProps; +>x.cProps : Symbol(C.cProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 11, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>cProps : Symbol(C.cProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 11, 14)) + + break; + } + + switch (true) { + default: + const never: never = x; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 64, 17)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) + + case x.kind === "a": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.aProps; +>x.aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>aProps : Symbol(A.aProps, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 1, 14)) + + // fallthrough + case x.kind === "b": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.bProps; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) + + // fallthrough + case x.kind === "c": +>x.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) +>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 0, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 5, 13), Decl(narrowByClauseExpressionInSwitchTrue6.ts, 10, 13)) + + x.cProps; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue6.ts, 18, 13)) + } +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.types new file mode 100644 index 0000000000000..4a96c67b07136 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.types @@ -0,0 +1,222 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue6.ts] //// + +=== narrowByClauseExpressionInSwitchTrue6.ts === +interface A { + kind: "a"; +>kind : "a" + + aProps: string; +>aProps : string +} + +interface B { + kind: "b"; +>kind : "b" + + bProps: string; +>bProps : string +} + +interface C { + kind: "c"; +>kind : "c" + + cProps: string; +>cProps : string +} + + +type MyType = A | B | C; +>MyType : A | B | C + +function isA(x: MyType) { +>isA : (x: MyType) => void +>x : MyType + + switch (true) { +>true : true + + default: + const never: never = x; +>never : never +>x : never + + case x.kind === "a": +>x.kind === "a" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"a" : "a" + + x.aProps; +>x.aProps : string +>x : A +>aProps : string + + break; + case x.kind === "b": +>x.kind === "b" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"b" : "b" + + x.bProps; +>x.bProps : string +>x : B +>bProps : string + + break; + case x.kind === "c": +>x.kind === "c" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"c" : "c" + + x.cProps; +>x.cProps : string +>x : C +>cProps : string + + break; + } + + switch (true) { +>true : true + + default: + const never: never = x; +>never : never +>x : never + + case x.kind === "a": { +>x.kind === "a" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"a" : "a" + + x.aProps; +>x.aProps : string +>x : A +>aProps : string + + break; + } + case x.kind === "b": { +>x.kind === "b" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"b" : "b" + + x.bProps; +>x.bProps : string +>x : B +>bProps : string + + break; + } + case x.kind === "c": { +>x.kind === "c" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"c" : "c" + + x.cProps; +>x.cProps : string +>x : C +>cProps : string + + break; + } + } + + switch (true) { +>true : true + + default: + x.aProps; +>x.aProps : string +>x : A +>aProps : string + + break; + case x.kind === "b": +>x.kind === "b" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"b" : "b" + + x.bProps; +>x.bProps : string +>x : B +>bProps : string + + break; + case x.kind === "c": +>x.kind === "c" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"c" : "c" + + x.cProps; +>x.cProps : string +>x : C +>cProps : string + + break; + } + + switch (true) { +>true : true + + default: + const never: never = x; +>never : never +>x : never + + case x.kind === "a": +>x.kind === "a" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"a" : "a" + + x.aProps; +>x.aProps : string +>x : A +>aProps : string + + // fallthrough + case x.kind === "b": +>x.kind === "b" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"b" : "b" + + x.bProps; +>x.bProps : any +>x : A | B +>bProps : any + + // fallthrough + case x.kind === "c": +>x.kind === "c" : boolean +>x.kind : "a" | "b" | "c" +>x : MyType +>kind : "a" | "b" | "c" +>"c" : "c" + + x.cProps; +>x.cProps : any +>x : MyType +>cProps : any + } +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.errors.txt b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.errors.txt new file mode 100644 index 0000000000000..ae09d39b7ca88 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.errors.txt @@ -0,0 +1,90 @@ +narrowByClauseExpressionInSwitchTrue7.ts(80,19): error TS2322: Type 'Derived2' is not assignable to type 'never'. + + +==== narrowByClauseExpressionInSwitchTrue7.ts (1 errors) ==== + class Base { + basey: string = ""; + } + + class Derived1 extends Base { + d: string = ""; + } + + class Derived2 extends Base { + d: string = ""; + other: string = ""; + } + + function classy(base: Base, someDerived: Derived1 | Derived2) { + switch (true) { + case base instanceof Derived1: + base.d + // fallthrough + default: + base.basey + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d + break; + case someDerived instanceof Derived2: + someDerived.d + break + default: + const never: never = someDerived; + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d + // fallthrough + case someDerived instanceof Derived2: + someDerived.d + break + default: + const never: never = someDerived; + } + + switch (true) { + default: + const never: never = someDerived; + case someDerived instanceof Derived1: + someDerived.d; + someDerived.basey; + break + case someDerived instanceof Derived2: + someDerived.d; + someDerived.other; + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d; + someDerived.basey; + break + default: + const never: never = someDerived; + case someDerived instanceof Derived2: + someDerived.d; + someDerived.other; + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d; + someDerived.basey; + break + case someDerived instanceof Derived2: + someDerived.d; + someDerived.other; + default: + someDerived.d; + someDerived.other; + const never: never = someDerived; + ~~~~~ +!!! error TS2322: Type 'Derived2' is not assignable to type 'never'. + } + + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.symbols new file mode 100644 index 0000000000000..ad0dd8f89d894 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.symbols @@ -0,0 +1,229 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue7.ts] //// + +=== narrowByClauseExpressionInSwitchTrue7.ts === +class Base { +>Base : Symbol(Base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 0)) + + basey: string = ""; +>basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) +} + +class Derived1 extends Base { +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) +>Base : Symbol(Base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 0)) + + d: string = ""; +>d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) +} + +class Derived2 extends Base { +>Derived2 : Symbol(Derived2, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 6, 1)) +>Base : Symbol(Base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 0)) + + d: string = ""; +>d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) + + other: string = ""; +>other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) +} + +function classy(base: Base, someDerived: Derived1 | Derived2) { +>classy : Symbol(classy, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 11, 1)) +>base : Symbol(base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 16)) +>Base : Symbol(Base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 0)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) +>Derived2 : Symbol(Derived2, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 6, 1)) + + switch (true) { + case base instanceof Derived1: +>base : Symbol(base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 16)) +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) + + base.d +>base.d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) +>base : Symbol(base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 16)) +>d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) + + // fallthrough + default: + base.basey +>base.basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) +>base : Symbol(base, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 16)) +>basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) + } + + switch (true) { + case someDerived instanceof Derived1: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) + + someDerived.d +>someDerived.d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) + + break; + case someDerived instanceof Derived2: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived2 : Symbol(Derived2, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 6, 1)) + + someDerived.d +>someDerived.d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) + + break + default: + const never: never = someDerived; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 30, 17)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) + } + + switch (true) { + case someDerived instanceof Derived1: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) + + someDerived.d +>someDerived.d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) + + // fallthrough + case someDerived instanceof Derived2: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived2 : Symbol(Derived2, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 6, 1)) + + someDerived.d +>someDerived.d : Symbol(d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29), Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29), Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) + + break + default: + const never: never = someDerived; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 41, 17)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) + } + + switch (true) { + default: + const never: never = someDerived; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 46, 17)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) + + case someDerived instanceof Derived1: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) + + someDerived.d; +>someDerived.d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) + + someDerived.basey; +>someDerived.basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) + + break + case someDerived instanceof Derived2: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived2 : Symbol(Derived2, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 6, 1)) + + someDerived.d; +>someDerived.d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) + + someDerived.other; +>someDerived.other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) + } + + switch (true) { + case someDerived instanceof Derived1: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) + + someDerived.d; +>someDerived.d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) + + someDerived.basey; +>someDerived.basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) + + break + default: + const never: never = someDerived; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 62, 17)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) + + case someDerived instanceof Derived2: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived2 : Symbol(Derived2, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 6, 1)) + + someDerived.d; +>someDerived.d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) + + someDerived.other; +>someDerived.other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) + } + + switch (true) { + case someDerived instanceof Derived1: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived1 : Symbol(Derived1, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 2, 1)) + + someDerived.d; +>someDerived.d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived1.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 4, 29)) + + someDerived.basey; +>someDerived.basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>basey : Symbol(Base.basey, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 0, 12)) + + break + case someDerived instanceof Derived2: +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>Derived2 : Symbol(Derived2, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 6, 1)) + + someDerived.d; +>someDerived.d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) + + someDerived.other; +>someDerived.other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) + + default: + someDerived.d; +>someDerived.d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>d : Symbol(Derived2.d, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 8, 29)) + + someDerived.other; +>someDerived.other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) +>other : Symbol(Derived2.other, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 9, 19)) + + const never: never = someDerived; +>never : Symbol(never, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 79, 17)) +>someDerived : Symbol(someDerived, Decl(narrowByClauseExpressionInSwitchTrue7.ts, 13, 27)) + } + +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.types new file mode 100644 index 0000000000000..a783c583b22f3 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue7.types @@ -0,0 +1,253 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue7.ts] //// + +=== narrowByClauseExpressionInSwitchTrue7.ts === +class Base { +>Base : Base + + basey: string = ""; +>basey : string +>"" : "" +} + +class Derived1 extends Base { +>Derived1 : Derived1 +>Base : Base + + d: string = ""; +>d : string +>"" : "" +} + +class Derived2 extends Base { +>Derived2 : Derived2 +>Base : Base + + d: string = ""; +>d : string +>"" : "" + + other: string = ""; +>other : string +>"" : "" +} + +function classy(base: Base, someDerived: Derived1 | Derived2) { +>classy : (base: Base, someDerived: Derived1 | Derived2) => void +>base : Base +>someDerived : Derived1 | Derived2 + + switch (true) { +>true : true + + case base instanceof Derived1: +>base instanceof Derived1 : boolean +>base : Base +>Derived1 : typeof Derived1 + + base.d +>base.d : string +>base : Derived1 +>d : string + + // fallthrough + default: + base.basey +>base.basey : string +>base : Base +>basey : string + } + + switch (true) { +>true : true + + case someDerived instanceof Derived1: +>someDerived instanceof Derived1 : boolean +>someDerived : Derived1 | Derived2 +>Derived1 : typeof Derived1 + + someDerived.d +>someDerived.d : string +>someDerived : Derived1 +>d : string + + break; + case someDerived instanceof Derived2: +>someDerived instanceof Derived2 : boolean +>someDerived : Derived1 | Derived2 +>Derived2 : typeof Derived2 + + someDerived.d +>someDerived.d : string +>someDerived : Derived2 +>d : string + + break + default: + const never: never = someDerived; +>never : never +>someDerived : never + } + + switch (true) { +>true : true + + case someDerived instanceof Derived1: +>someDerived instanceof Derived1 : boolean +>someDerived : Derived1 | Derived2 +>Derived1 : typeof Derived1 + + someDerived.d +>someDerived.d : string +>someDerived : Derived1 +>d : string + + // fallthrough + case someDerived instanceof Derived2: +>someDerived instanceof Derived2 : boolean +>someDerived : Derived1 | Derived2 +>Derived2 : typeof Derived2 + + someDerived.d +>someDerived.d : string +>someDerived : Derived1 | Derived2 +>d : string + + break + default: + const never: never = someDerived; +>never : never +>someDerived : never + } + + switch (true) { +>true : true + + default: + const never: never = someDerived; +>never : never +>someDerived : never + + case someDerived instanceof Derived1: +>someDerived instanceof Derived1 : boolean +>someDerived : Derived1 | Derived2 +>Derived1 : typeof Derived1 + + someDerived.d; +>someDerived.d : string +>someDerived : Derived1 +>d : string + + someDerived.basey; +>someDerived.basey : string +>someDerived : Derived1 +>basey : string + + break + case someDerived instanceof Derived2: +>someDerived instanceof Derived2 : boolean +>someDerived : Derived1 | Derived2 +>Derived2 : typeof Derived2 + + someDerived.d; +>someDerived.d : string +>someDerived : Derived2 +>d : string + + someDerived.other; +>someDerived.other : string +>someDerived : Derived2 +>other : string + } + + switch (true) { +>true : true + + case someDerived instanceof Derived1: +>someDerived instanceof Derived1 : boolean +>someDerived : Derived1 | Derived2 +>Derived1 : typeof Derived1 + + someDerived.d; +>someDerived.d : string +>someDerived : Derived1 +>d : string + + someDerived.basey; +>someDerived.basey : string +>someDerived : Derived1 +>basey : string + + break + default: + const never: never = someDerived; +>never : never +>someDerived : never + + case someDerived instanceof Derived2: +>someDerived instanceof Derived2 : boolean +>someDerived : Derived1 | Derived2 +>Derived2 : typeof Derived2 + + someDerived.d; +>someDerived.d : string +>someDerived : Derived2 +>d : string + + someDerived.other; +>someDerived.other : string +>someDerived : Derived2 +>other : string + } + + switch (true) { +>true : true + + case someDerived instanceof Derived1: +>someDerived instanceof Derived1 : boolean +>someDerived : Derived1 | Derived2 +>Derived1 : typeof Derived1 + + someDerived.d; +>someDerived.d : string +>someDerived : Derived1 +>d : string + + someDerived.basey; +>someDerived.basey : string +>someDerived : Derived1 +>basey : string + + break + case someDerived instanceof Derived2: +>someDerived instanceof Derived2 : boolean +>someDerived : Derived1 | Derived2 +>Derived2 : typeof Derived2 + + someDerived.d; +>someDerived.d : string +>someDerived : Derived2 +>d : string + + someDerived.other; +>someDerived.other : string +>someDerived : Derived2 +>other : string + + default: + someDerived.d; +>someDerived.d : string +>someDerived : Derived2 +>d : string + + someDerived.other; +>someDerived.other : string +>someDerived : Derived2 +>other : string + + const never: never = someDerived; +>never : never +>someDerived : Derived2 + } + +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.symbols new file mode 100644 index 0000000000000..ec14234e62b6c --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.symbols @@ -0,0 +1,57 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue8.ts] //// + +=== narrowByClauseExpressionInSwitchTrue8.ts === +function foo(cond1: boolean, cond2: boolean) { +>foo : Symbol(foo, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 0)) +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 13)) +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 28)) + + switch (true) { + case cond1: +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 13)) + + cond1; // Should be true +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 13)) + + // ^? + cond2; // Should be boolean +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 28)) + + // ^? + break; + + case cond2: +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 28)) + + cond1; // Should be false? +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 13)) + + // ^? + cond2; // Should be true +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 28)) + + // ^? + break; + + default: + cond1; // Should be false? +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 13)) + + // ^? + cond2; // Should be false? +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 28)) + + // ^? + break; + } + + cond1; // Should be boolean +>cond1 : Symbol(cond1, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 13)) + + // ^? + cond2; // Should be boolean +>cond2 : Symbol(cond2, Decl(narrowByClauseExpressionInSwitchTrue8.ts, 0, 28)) + + // ^? +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.types new file mode 100644 index 0000000000000..45230dc5e12b9 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.types @@ -0,0 +1,59 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue8.ts] //// + +=== narrowByClauseExpressionInSwitchTrue8.ts === +function foo(cond1: boolean, cond2: boolean) { +>foo : (cond1: boolean, cond2: boolean) => void +>cond1 : boolean +>cond2 : boolean + + switch (true) { +>true : true + + case cond1: +>cond1 : boolean + + cond1; // Should be true +>cond1 : true + + // ^? + cond2; // Should be boolean +>cond2 : boolean + + // ^? + break; + + case cond2: +>cond2 : boolean + + cond1; // Should be false? +>cond1 : false + + // ^? + cond2; // Should be true +>cond2 : true + + // ^? + break; + + default: + cond1; // Should be false? +>cond1 : false + + // ^? + cond2; // Should be false? +>cond2 : false + + // ^? + break; + } + + cond1; // Should be boolean +>cond1 : boolean + + // ^? + cond2; // Should be boolean +>cond2 : boolean + + // ^? +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.symbols b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.symbols new file mode 100644 index 0000000000000..1cbdfc55b276d --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.symbols @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue9.ts] //// + +=== narrowByClauseExpressionInSwitchTrue9.ts === +interface IProps { +>IProps : Symbol(IProps, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 0, 0)) + + one: boolean; +>one : Symbol(IProps.one, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 0, 18)) +} + +class Foo { +>Foo : Symbol(Foo, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 2, 1)) + + mine: string = ""; +>mine : Symbol(Foo.mine, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 4, 11)) + + myMethod(x: IProps) { +>myMethod : Symbol(Foo.myMethod, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 5, 22)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 7, 13)) +>IProps : Symbol(IProps, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 0, 0)) + + const { one } = x; +>one : Symbol(one, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 8, 15)) +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 7, 13)) + + switch (true) { + case one: +>one : Symbol(one, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 8, 15)) + + break; + default: + let x = this.mine; +>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 13, 19)) +>this.mine : Symbol(Foo.mine, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 4, 11)) +>this : Symbol(Foo, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 2, 1)) +>mine : Symbol(Foo.mine, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 4, 11)) + } + } +} + diff --git a/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.types b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.types new file mode 100644 index 0000000000000..75557462a5b20 --- /dev/null +++ b/tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.types @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/narrowByClauseExpressionInSwitchTrue9.ts] //// + +=== narrowByClauseExpressionInSwitchTrue9.ts === +interface IProps { + one: boolean; +>one : boolean +} + +class Foo { +>Foo : Foo + + mine: string = ""; +>mine : string +>"" : "" + + myMethod(x: IProps) { +>myMethod : (x: IProps) => void +>x : IProps + + const { one } = x; +>one : boolean +>x : IProps + + switch (true) { +>true : true + + case one: +>one : boolean + + break; + default: + let x = this.mine; +>x : string +>this.mine : string +>this : this +>mine : string + } + } +} + diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue1.ts similarity index 100% rename from tests/cases/compiler/narrowByClauseExpressionInSwitchTrue.ts rename to tests/cases/compiler/narrowByClauseExpressionInSwitchTrue1.ts diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue10.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue10.ts new file mode 100644 index 0000000000000..7d48369ca34e0 --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue10.ts @@ -0,0 +1,56 @@ +// @strict: true +// @noEmit: true + +function foo(cond1: boolean, cond2: boolean) { + switch (true) { + case cond1 || cond2: + cond1; // boolean + // ^? + cond2; // boolean + // ^? + break; + + case cond2: + cond1; // false + // ^? + cond2;; // never + // ^? + break; + + default: + cond1; // false + // ^? + cond2; // false + // ^? + break; + } + + cond1; // boolean + // ^? + cond2; // boolean + // ^? +} + +function blah(cond1: boolean, cond2: boolean) { + if (cond1 || cond2) { + cond1; // boolean + // ^? + cond2; // boolean + // ^? + } else if (cond2) { + cond1; // false + // ^? + cond2; // never + // ^? + } else { + cond1; // false + // ^? + cond2; // false + // ^? + } + + cond1; // boolean + // ^? + cond2; // boolean + // ^? +} diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue2.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue2.ts new file mode 100644 index 0000000000000..461e3505c393a --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue2.ts @@ -0,0 +1,29 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/55986 + +declare const f: 'a' | 'b' | 'c'; + +switch(true) { + case f === 'a': + case f === 'b': + f; + break + default: + f; +} + +f; + +switch(true) { + case f === 'a': + f; + case f === 'b': + f; + break + default: + f; +} + +f; diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue3.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue3.ts new file mode 100644 index 0000000000000..d0dbafccbb108 --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue3.ts @@ -0,0 +1,22 @@ +// @strict: true +// @noEmit: true + +type Shape = + | { kind: "circle", radius: number } + | { kind: "square", sideLength: number } + +function wat(shape: Shape) { + switch (true) { + case shape.kind === "circle": + return Math.PI * shape.radius ** 2; + case shape.kind === "circle": // should error + } + + if (shape.kind === "circle") { + return Math.PI * shape.radius ** 2; + } + else if (shape.kind === "circle") { + // ~~~~ + // Property 'kind' does not exist on type 'never'. + } +} diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue4.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue4.ts new file mode 100644 index 0000000000000..15596fd7ad11a --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue4.ts @@ -0,0 +1,12 @@ +// @strict: true +// @noEmit: true + +declare const f: 'a' | 'b' | 'c'; + +switch (true) { + case f === "a": + default: + f; + case f === "b": + f; +} diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue5.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue5.ts new file mode 100644 index 0000000000000..f4aee3ff151e1 --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue5.ts @@ -0,0 +1,133 @@ +// @strict: true +// @noEmit: true + +type A = { kind: "A", value: number }; +type B = { kind: "B", name: string }; +type C = { kind: "C", cond: boolean }; +type D = { kind: "D", value: boolean }; +type E = { kind: "E", x: number, y: number }; + +type All = A | B | C | D | E; + +function fn1switch(input: All) { + switch (true) { + case input.kind === "A": + case input.kind === "B": + if (input.kind === "A") { + return; + } + + input; // Should be B; + // ^? + + // fallthrough + case input.kind === "C": + input; // Should be B | C + // ^? + break; + default: + input; // Should be D | E + // ^? + } + + input; // Should not be A + // ^? +} + +function fn1ifelse(input: All) { + if (input.kind === "A" || input.kind === "B") { + if (input.kind === "A") { + return; + } + + input; // Should be B; + // ^? + } + if (input.kind === "C" || input.kind === "B") { + input; // Should be B | C + // ^? + } + else { + input; // Should be D | E + // ^? + } + + input; // Should not be A + // ^? +} + +function fn2switch(input: All) { + switch (true) { + case input.kind === "A": + case input.kind === "B": + if (input.kind === "A") { + return; + } + + input; // Should be B; + // ^? + + // fallthrough + case input.kind === "C": + input; // Should be B | C + // ^? + break; + default: + input; // Should be D | E + // ^? + return; + } + + input; // Should be B | C + // ^? +} + +function fn2ifelse(input: All) { + if (input.kind === "A" || input.kind === "B") { + if (input.kind === "A") { + return; + } + + input; // Should be B; + // ^? + } + if (input.kind === "C" || input.kind === "B") { + input; // Should be B | C + // ^? + } + else { + input; // Should be D | E + // ^? + return; + } + + input; // Should be B | C + // ^? +} + +function fn3switch(input: All) { + switch (true) { + case input.kind === "A": + case input.kind === "B": + if (input.kind === "A") { + return; + } + + input; // Should be B; + // ^? + + // fallthrough + default: + input; // Should be B | D | E + // ^? + break; + + case input.kind === "C": + input; // Should be C + // ^? + break; + } + + input; // Should not be A + // ^? +} diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue6.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue6.ts new file mode 100644 index 0000000000000..491355b79e906 --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue6.ts @@ -0,0 +1,78 @@ +// @strict: true +// @noEmit: true + +interface A { + kind: "a"; + aProps: string; +} + +interface B { + kind: "b"; + bProps: string; +} + +interface C { + kind: "c"; + cProps: string; +} + + +type MyType = A | B | C; + +function isA(x: MyType) { + switch (true) { + default: + const never: never = x; + case x.kind === "a": + x.aProps; + break; + case x.kind === "b": + x.bProps; + break; + case x.kind === "c": + x.cProps; + break; + } + + switch (true) { + default: + const never: never = x; + case x.kind === "a": { + x.aProps; + break; + } + case x.kind === "b": { + x.bProps; + break; + } + case x.kind === "c": { + x.cProps; + break; + } + } + + switch (true) { + default: + x.aProps; + break; + case x.kind === "b": + x.bProps; + break; + case x.kind === "c": + x.cProps; + break; + } + + switch (true) { + default: + const never: never = x; + case x.kind === "a": + x.aProps; + // fallthrough + case x.kind === "b": + x.bProps; + // fallthrough + case x.kind === "c": + x.cProps; + } +} diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue7.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue7.ts new file mode 100644 index 0000000000000..d482d8fa033a4 --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue7.ts @@ -0,0 +1,86 @@ +// @strict: true +// @noEmit: true + +class Base { + basey: string = ""; +} + +class Derived1 extends Base { + d: string = ""; +} + +class Derived2 extends Base { + d: string = ""; + other: string = ""; +} + +function classy(base: Base, someDerived: Derived1 | Derived2) { + switch (true) { + case base instanceof Derived1: + base.d + // fallthrough + default: + base.basey + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d + break; + case someDerived instanceof Derived2: + someDerived.d + break + default: + const never: never = someDerived; + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d + // fallthrough + case someDerived instanceof Derived2: + someDerived.d + break + default: + const never: never = someDerived; + } + + switch (true) { + default: + const never: never = someDerived; + case someDerived instanceof Derived1: + someDerived.d; + someDerived.basey; + break + case someDerived instanceof Derived2: + someDerived.d; + someDerived.other; + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d; + someDerived.basey; + break + default: + const never: never = someDerived; + case someDerived instanceof Derived2: + someDerived.d; + someDerived.other; + } + + switch (true) { + case someDerived instanceof Derived1: + someDerived.d; + someDerived.basey; + break + case someDerived instanceof Derived2: + someDerived.d; + someDerived.other; + default: + someDerived.d; + someDerived.other; + const never: never = someDerived; + } + +} diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue8.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue8.ts new file mode 100644 index 0000000000000..3572817cba99b --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue8.ts @@ -0,0 +1,32 @@ +// @strict: true +// @noEmit: true + +function foo(cond1: boolean, cond2: boolean) { + switch (true) { + case cond1: + cond1; // Should be true + // ^? + cond2; // Should be boolean + // ^? + break; + + case cond2: + cond1; // Should be false? + // ^? + cond2; // Should be true + // ^? + break; + + default: + cond1; // Should be false? + // ^? + cond2; // Should be false? + // ^? + break; + } + + cond1; // Should be boolean + // ^? + cond2; // Should be boolean + // ^? +} diff --git a/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue9.ts b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue9.ts new file mode 100644 index 0000000000000..1f8942d90b1fb --- /dev/null +++ b/tests/cases/compiler/narrowByClauseExpressionInSwitchTrue9.ts @@ -0,0 +1,20 @@ +// @strict: true +// @noEmit: true + +interface IProps { + one: boolean; +} + +class Foo { + mine: string = ""; + + myMethod(x: IProps) { + const { one } = x; + switch (true) { + case one: + break; + default: + let x = this.mine; + } + } +} From d1a2e7e730cb8ebd44662ece6b263e2d4d885da2 Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Sat, 7 Oct 2023 06:18:08 +0000 Subject: [PATCH 2/7] Update package-lock.json --- package-lock.json | 56 +++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index d78e55a1e51bb..b9ccfc450477b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -578,9 +578,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -938,9 +938,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", + "version": "20.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", + "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==", "dev": true }, "node_modules/@types/semver": { @@ -1801,15 +1801,15 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2143,12 +2143,12 @@ } }, "node_modules/flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", "dev": true, "dependencies": { - "flatted": "^3.2.7", + "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, @@ -4178,9 +4178,9 @@ } }, "@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true }, "@humanwhocodes/config-array": { @@ -4468,9 +4468,9 @@ "dev": true }, "@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", + "version": "20.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", + "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==", "dev": true }, "@types/semver": { @@ -5087,15 +5087,15 @@ "dev": true }, "eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5329,12 +5329,12 @@ "dev": true }, "flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", "dev": true, "requires": { - "flatted": "^3.2.7", + "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" } From 61a96b1641abe24c4adc3633eb936df89eb991f2 Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Sun, 8 Oct 2023 06:19:04 +0000 Subject: [PATCH 3/7] Update package-lock.json --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9ccfc450477b..facac0374d15e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2654,9 +2654,9 @@ "dev": true }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "dependencies": { "json-buffer": "3.0.1" @@ -5705,9 +5705,9 @@ "dev": true }, "keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "requires": { "json-buffer": "3.0.1" From 9144836360cc6bb4e930baf7afd3aa9699572929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 9 Oct 2023 20:36:16 +0200 Subject: [PATCH 4/7] Fixed type narrowing in switch statements with parenthesized expressions (#56035) --- src/compiler/checker.ts | 2 +- ...rowByParenthesizedSwitchExpression.symbols | 66 +++++++++++++++++++ ...arrowByParenthesizedSwitchExpression.types | 63 ++++++++++++++++++ .../narrowByParenthesizedSwitchExpression.ts | 32 +++++++++ 4 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/narrowByParenthesizedSwitchExpression.symbols create mode 100644 tests/baselines/reference/narrowByParenthesizedSwitchExpression.types create mode 100644 tests/cases/compiler/narrowByParenthesizedSwitchExpression.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2c9344679abd8..4c31ece8602d0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27446,7 +27446,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeAtSwitchClause(flow: FlowSwitchClause): FlowType { - const expr = flow.switchStatement.expression; + const expr = skipParentheses(flow.switchStatement.expression); const flowType = getTypeAtFlowNode(flow.antecedent); let type = getTypeFromFlowType(flowType); if (isMatchingReference(reference, expr)) { diff --git a/tests/baselines/reference/narrowByParenthesizedSwitchExpression.symbols b/tests/baselines/reference/narrowByParenthesizedSwitchExpression.symbols new file mode 100644 index 0000000000000..4bcf3c49d1644 --- /dev/null +++ b/tests/baselines/reference/narrowByParenthesizedSwitchExpression.symbols @@ -0,0 +1,66 @@ +//// [tests/cases/compiler/narrowByParenthesizedSwitchExpression.ts] //// + +=== narrowByParenthesizedSwitchExpression.ts === +interface Base { +>Base : Symbol(Base, Decl(narrowByParenthesizedSwitchExpression.ts, 0, 0)) + + type: "foo" | "bar"; +>type : Symbol(Base.type, Decl(narrowByParenthesizedSwitchExpression.ts, 0, 16)) +} + +interface Foo extends Base { +>Foo : Symbol(Foo, Decl(narrowByParenthesizedSwitchExpression.ts, 2, 1)) +>Base : Symbol(Base, Decl(narrowByParenthesizedSwitchExpression.ts, 0, 0)) + + type: "foo"; +>type : Symbol(Foo.type, Decl(narrowByParenthesizedSwitchExpression.ts, 4, 28)) + + foo: string; +>foo : Symbol(Foo.foo, Decl(narrowByParenthesizedSwitchExpression.ts, 5, 14)) +} + +interface Bar extends Base { +>Bar : Symbol(Bar, Decl(narrowByParenthesizedSwitchExpression.ts, 7, 1)) +>Base : Symbol(Base, Decl(narrowByParenthesizedSwitchExpression.ts, 0, 0)) + + type: "bar"; +>type : Symbol(Bar.type, Decl(narrowByParenthesizedSwitchExpression.ts, 9, 28)) + + bar: number; +>bar : Symbol(Bar.bar, Decl(narrowByParenthesizedSwitchExpression.ts, 10, 14)) +} + +function getV(): Foo | Bar { +>getV : Symbol(getV, Decl(narrowByParenthesizedSwitchExpression.ts, 12, 1)) +>Foo : Symbol(Foo, Decl(narrowByParenthesizedSwitchExpression.ts, 2, 1)) +>Bar : Symbol(Bar, Decl(narrowByParenthesizedSwitchExpression.ts, 7, 1)) + + return null!; +} + +const v = getV(); +>v : Symbol(v, Decl(narrowByParenthesizedSwitchExpression.ts, 18, 5)) +>getV : Symbol(getV, Decl(narrowByParenthesizedSwitchExpression.ts, 12, 1)) + +switch ((v.type)) { +>v.type : Symbol(type, Decl(narrowByParenthesizedSwitchExpression.ts, 4, 28), Decl(narrowByParenthesizedSwitchExpression.ts, 9, 28)) +>v : Symbol(v, Decl(narrowByParenthesizedSwitchExpression.ts, 18, 5)) +>type : Symbol(type, Decl(narrowByParenthesizedSwitchExpression.ts, 4, 28), Decl(narrowByParenthesizedSwitchExpression.ts, 9, 28)) + + case "bar": + v.bar; +>v.bar : Symbol(Bar.bar, Decl(narrowByParenthesizedSwitchExpression.ts, 10, 14)) +>v : Symbol(v, Decl(narrowByParenthesizedSwitchExpression.ts, 18, 5)) +>bar : Symbol(Bar.bar, Decl(narrowByParenthesizedSwitchExpression.ts, 10, 14)) + + break; + + case "foo": + v.foo; +>v.foo : Symbol(Foo.foo, Decl(narrowByParenthesizedSwitchExpression.ts, 5, 14)) +>v : Symbol(v, Decl(narrowByParenthesizedSwitchExpression.ts, 18, 5)) +>foo : Symbol(Foo.foo, Decl(narrowByParenthesizedSwitchExpression.ts, 5, 14)) + + break; +} + diff --git a/tests/baselines/reference/narrowByParenthesizedSwitchExpression.types b/tests/baselines/reference/narrowByParenthesizedSwitchExpression.types new file mode 100644 index 0000000000000..6601417a33c13 --- /dev/null +++ b/tests/baselines/reference/narrowByParenthesizedSwitchExpression.types @@ -0,0 +1,63 @@ +//// [tests/cases/compiler/narrowByParenthesizedSwitchExpression.ts] //// + +=== narrowByParenthesizedSwitchExpression.ts === +interface Base { + type: "foo" | "bar"; +>type : "foo" | "bar" +} + +interface Foo extends Base { + type: "foo"; +>type : "foo" + + foo: string; +>foo : string +} + +interface Bar extends Base { + type: "bar"; +>type : "bar" + + bar: number; +>bar : number +} + +function getV(): Foo | Bar { +>getV : () => Foo | Bar + + return null!; +>null! : never +} + +const v = getV(); +>v : Foo | Bar +>getV() : Foo | Bar +>getV : () => Foo | Bar + +switch ((v.type)) { +>(v.type) : "foo" | "bar" +>v.type : "foo" | "bar" +>v : Foo | Bar +>type : "foo" | "bar" + + case "bar": +>"bar" : "bar" + + v.bar; +>v.bar : number +>v : Bar +>bar : number + + break; + + case "foo": +>"foo" : "foo" + + v.foo; +>v.foo : string +>v : Foo +>foo : string + + break; +} + diff --git a/tests/cases/compiler/narrowByParenthesizedSwitchExpression.ts b/tests/cases/compiler/narrowByParenthesizedSwitchExpression.ts new file mode 100644 index 0000000000000..2f2d9330ce1d8 --- /dev/null +++ b/tests/cases/compiler/narrowByParenthesizedSwitchExpression.ts @@ -0,0 +1,32 @@ +// @strict: true +// @noEmit: true + +interface Base { + type: "foo" | "bar"; +} + +interface Foo extends Base { + type: "foo"; + foo: string; +} + +interface Bar extends Base { + type: "bar"; + bar: number; +} + +function getV(): Foo | Bar { + return null!; +} + +const v = getV(); + +switch ((v.type)) { + case "bar": + v.bar; + break; + + case "foo": + v.foo; + break; +} From d0d406747d580ec4972dc411a9f158c232695987 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 9 Oct 2023 11:38:15 -0700 Subject: [PATCH 5/7] Add type reference directive for all visited references to ambient modules (#56015) --- src/compiler/checker.ts | 5 +++ src/compiler/emitter.ts | 1 + src/compiler/transformers/declarations.ts | 27 ++++++++++++++-- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 5 ++- ...larationEmitBundleWithAmbientReferences.js | 1 + ...onEmitTripleSlashReferenceAmbientModule.js | 31 +++++++++++++++++++ ...ImportHelpersCollisions2(module=node16).js | 1 + ...portHelpersCollisions2(module=nodenext).js | 1 + ...ModulesImportAssignments(module=node16).js | 3 ++ ...dulesImportAssignments(module=nodenext).js | 3 ++ ...ImportHelpersCollisions2(module=node16).js | 2 ++ ...portHelpersCollisions2(module=nodenext).js | 2 ++ ...ImportHelpersCollisions3(module=node16).js | 2 ++ ...portHelpersCollisions3(module=nodenext).js | 2 ++ ...onEmitTripleSlashReferenceAmbientModule.ts | 20 ++++++++++++ 16 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/declarationEmitTripleSlashReferenceAmbientModule.js create mode 100644 tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4c31ece8602d0..6098245cb6c67 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -47930,6 +47930,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled); }, isImportRequiredByAugmentation, + tryFindAmbientModule: moduleReferenceExpression => { + const node = getParseTreeNode(moduleReferenceExpression); + const moduleSpecifier = node && isStringLiteralLike(node) ? node.text : undefined; + return moduleSpecifier !== undefined ? tryFindAmbientModule(moduleSpecifier, /*withAugmentations*/ true) : undefined; + }, }; function isImportRequiredByAugmentation(node: ImportDeclaration) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 3d035053761af..463651bdb0049 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1182,6 +1182,7 @@ export const notImplementedResolver: EmitResolver = { isBindingCapturedByNode: notImplemented, getDeclarationStatementsForSourceFile: notImplemented, isImportRequiredByAugmentation: notImplemented, + tryFindAmbientModule: notImplemented, }; /** diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 05b5ad1c8b9b4..512c2eb4704f8 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -212,6 +212,7 @@ import { TransformationContext, transformNodes, tryCast, + tryGetModuleSpecifierFromDeclaration, TypeAliasDeclaration, TypeNode, TypeParameterDeclaration, @@ -345,6 +346,18 @@ export function transformDeclarations(context: TransformationContext) { refs.set(getOriginalNodeId(container), container); } + function trackReferencedAmbientModuleFromImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportTypeNode) { + const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(node); + const symbol = moduleSpecifier && resolver.tryFindAmbientModule(moduleSpecifier); + if (symbol?.declarations) { + for (const decl of symbol.declarations) { + if (isAmbientModule(decl) && getSourceFileOfNode(decl) !== currentSourceFile) { + trackReferencedAmbientModule(decl, symbol); + } + } + } + } + function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) { if (symbolAccessibilityResult.accessibility === SymbolAccessibility.Accessible) { // Add aliases back onto the possible imports list if they're not there so we can try them again with updated visibility info @@ -1312,6 +1325,7 @@ export function transformDeclarations(context: TransformationContext) { } case SyntaxKind.ImportType: { if (!isLiteralImportTypeNode(input)) return cleanup(input); + trackReferencedAmbientModuleFromImport(input); return cleanup(factory.updateImportTypeNode( input, factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)), @@ -1370,6 +1384,7 @@ export function transformDeclarations(context: TransformationContext) { } resultHasScopeMarker = true; // Always visible if the parent node isn't dropped for being not visible + trackReferencedAmbientModuleFromImport(input); // Rewrite external module names if necessary return factory.updateExportDeclaration( input, @@ -1456,10 +1471,18 @@ export function transformDeclarations(context: TransformationContext) { if (shouldStripInternal(input)) return; switch (input.kind) { case SyntaxKind.ImportEqualsDeclaration: { - return transformImportEqualsDeclaration(input); + const transformed = transformImportEqualsDeclaration(input); + if (transformed) { + trackReferencedAmbientModuleFromImport(input); + } + return transformed; } case SyntaxKind.ImportDeclaration: { - return transformImportDeclaration(input); + const transformed = transformImportDeclaration(input); + if (transformed) { + trackReferencedAmbientModuleFromImport(input); + } + return transformed; } } if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9a185a4923249..a64c4c86b596d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5675,6 +5675,7 @@ export interface EmitResolver { isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean; getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined; isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; + tryFindAmbientModule(moduleReferenceExpression: Expression): Symbol | undefined; } // dprint-ignore diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 126b74d91dac7..8d4a3d2496993 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3975,12 +3975,13 @@ export function isFunctionSymbol(symbol: Symbol | undefined) { } /** @internal */ -export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode): StringLiteralLike | undefined { +export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode): StringLiteralLike | undefined { switch (node.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: return findAncestor(node.initializer, (node): node is RequireOrImportCall => isRequireCall(node, /*requireStringLiteralLikeArgument*/ true))?.arguments[0]; case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportDeclaration: return tryCast(node.moduleSpecifier, isStringLiteralLike); case SyntaxKind.ImportEqualsDeclaration: return tryCast(tryCast(node.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike); @@ -3992,6 +3993,8 @@ export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAcce return tryCast(node.parent.parent.moduleSpecifier, isStringLiteralLike); case SyntaxKind.ImportSpecifier: return tryCast(node.parent.parent.parent.moduleSpecifier, isStringLiteralLike); + case SyntaxKind.ImportType: + return isLiteralImportTypeNode(node) ? node.argument.literal : undefined; default: Debug.assertNever(node); } diff --git a/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js b/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js index 0d6946277ad26..ece01c1794a0b 100644 --- a/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js +++ b/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js @@ -37,6 +37,7 @@ define("conditional_directive_field", ["require", "exports"], function (require, //// [datastore.bundle.d.ts] +/// declare module "datastore_result" { import { Result } from "lib/result"; export type T = Result; diff --git a/tests/baselines/reference/declarationEmitTripleSlashReferenceAmbientModule.js b/tests/baselines/reference/declarationEmitTripleSlashReferenceAmbientModule.js new file mode 100644 index 0000000000000..b283b08edcd9e --- /dev/null +++ b/tests/baselines/reference/declarationEmitTripleSlashReferenceAmbientModule.js @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts] //// + +//// [index.d.ts] +declare module "url" { + export class Url {} + export function parse(): Url; +} + +//// [usage1.ts] +export { parse } from "url"; + +//// [usage2.ts] +import { parse } from "url"; +export const thing: import("url").Url = parse(); + +//// [usage3.ts] +import { parse } from "url"; +export const thing = parse(); + + + + +//// [usage1.d.ts] +/// +export { parse } from "url"; +//// [usage2.d.ts] +/// +export declare const thing: import("url").Url; +//// [usage3.d.ts] +/// +export declare const thing: import("url").Url; diff --git a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js index 7c584a828615c..0d0046de24daa 100644 --- a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js +++ b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js @@ -40,6 +40,7 @@ export * as fs from "fs"; //// [index.d.ts] +/// export * from "fs"; export * as fs from "fs"; //// [index.d.ts] diff --git a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js index 7c584a828615c..0d0046de24daa 100644 --- a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js +++ b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js @@ -40,6 +40,7 @@ export * as fs from "fs"; //// [index.d.ts] +/// export * from "fs"; export * as fs from "fs"; //// [index.d.ts] diff --git a/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js b/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js index e56ab00bb87c4..779a5236c5d5d 100644 --- a/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js +++ b/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js @@ -58,8 +58,11 @@ export { fs2 }; //// [index.d.ts] +/// export import fs2 = require("fs"); //// [index.d.ts] +/// export import fs2 = require("fs"); //// [file.d.ts] +/// export import fs2 = require("fs"); diff --git a/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js b/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js index e56ab00bb87c4..779a5236c5d5d 100644 --- a/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js +++ b/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js @@ -58,8 +58,11 @@ export { fs2 }; //// [index.d.ts] +/// export import fs2 = require("fs"); //// [index.d.ts] +/// export import fs2 = require("fs"); //// [file.d.ts] +/// export import fs2 = require("fs"); diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js index e8e9b78464c55..53eeb9bd5a78a 100644 --- a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js +++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js @@ -40,8 +40,10 @@ export * as fs from "fs"; //// [index.d.ts] +/// export * from "fs"; export * as fs from "fs"; //// [index.d.ts] +/// export * from "fs"; export * as fs from "fs"; diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js index e8e9b78464c55..53eeb9bd5a78a 100644 --- a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js +++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js @@ -40,8 +40,10 @@ export * as fs from "fs"; //// [index.d.ts] +/// export * from "fs"; export * as fs from "fs"; //// [index.d.ts] +/// export * from "fs"; export * as fs from "fs"; diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js index 8abf8ba9adac3..5f98164aaaa84 100644 --- a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js +++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js @@ -39,6 +39,8 @@ export { default } from "fs"; //// [index.d.ts] +/// export { default } from "fs"; //// [index.d.ts] +/// export { default } from "fs"; diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js index 8abf8ba9adac3..5f98164aaaa84 100644 --- a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js +++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js @@ -39,6 +39,8 @@ export { default } from "fs"; //// [index.d.ts] +/// export { default } from "fs"; //// [index.d.ts] +/// export { default } from "fs"; diff --git a/tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts b/tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts new file mode 100644 index 0000000000000..df9274fa371e2 --- /dev/null +++ b/tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts @@ -0,0 +1,20 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @noTypesAndSymbols: true + +// @Filename: /node_modules/@types/node/index.d.ts +declare module "url" { + export class Url {} + export function parse(): Url; +} + +// @Filename: /usage1.ts +export { parse } from "url"; + +// @Filename: /usage2.ts +import { parse } from "url"; +export const thing: import("url").Url = parse(); + +// @Filename: /usage3.ts +import { parse } from "url"; +export const thing = parse(); From 3516ca96e552ba82c4c7d9215adba4afc53eeedc Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 9 Oct 2023 16:05:11 -0700 Subject: [PATCH 6/7] pass program update level to getExternalFiles in tsserver plugins so plugins can make decision about their cache based on that (#56047) Co-authored-by: Andrew Branch --- src/compiler/tsbuildPublic.ts | 54 +++++++------- src/compiler/watchPublic.ts | 42 +++++------ src/compiler/watchUtilities.ts | 18 +++-- src/server/editorServices.ts | 60 +++++++-------- src/server/project.ts | 36 ++++----- .../unittests/tsserver/externalProjects.ts | 6 +- src/testRunner/unittests/tsserver/plugins.ts | 21 +++++- tests/baselines/reference/api/typescript.d.ts | 17 ++++- ...on-ts-extensions-with-wildcard-matching.js | 74 +++++++++++++++++-- 9 files changed, 213 insertions(+), 115 deletions(-) diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index 8512e52f07f86..070ad30f4c04b 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -14,7 +14,6 @@ import { CompilerHost, CompilerOptions, CompilerOptionsValue, - ConfigFileProgramReloadLevel, convertToRelativePath, copyProperties, createCompilerDiagnostic, @@ -95,6 +94,7 @@ import { ProgramBundleEmitBuildInfo, ProgramHost, ProgramMultiFileEmitBuildInfo, + ProgramUpdateLevel, readBuilderProgram, ReadBuildProgramHost, resolveConfigFileProjectName, @@ -287,7 +287,7 @@ export interface SolutionBuilder { // Testing only /** @internal */ getUpToDateStatusOfProject(project: string): UpToDateStatus; - /** @internal */ invalidateProject(configFilePath: ResolvedConfigFilePath, reloadLevel?: ConfigFileProgramReloadLevel): void; + /** @internal */ invalidateProject(configFilePath: ResolvedConfigFilePath, updateLevel?: ProgramUpdateLevel): void; /** @internal */ close(): void; } @@ -389,7 +389,7 @@ interface SolutionBuilderState extends WatchFactory; readonly diagnostics: Map; - readonly projectPendingBuild: Map; + readonly projectPendingBuild: Map; readonly projectErrorsReported: Map; readonly compilerHost: CompilerHost & ReadBuildProgramHost; @@ -795,13 +795,13 @@ function clearProjectStatus(state: SolutionBuilderStat state.diagnostics.delete(resolved); } -function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: ResolvedConfigFilePath, updateLevel: ProgramUpdateLevel) { const value = projectPendingBuild.get(proj); if (value === undefined) { - projectPendingBuild.set(proj, reloadLevel); + projectPendingBuild.set(proj, updateLevel); } - else if (value < reloadLevel) { - projectPendingBuild.set(proj, reloadLevel); + else if (value < updateLevel) { + projectPendingBuild.set(proj, updateLevel); } } @@ -815,7 +815,7 @@ function setupInitialBuild(state: SolutionBuilderState buildOrder.forEach(configFileName => state.projectPendingBuild.set( toResolvedConfigFilePath(state, configFileName), - ConfigFileProgramReloadLevel.None, + ProgramUpdateLevel.Update, ) ); @@ -1402,8 +1402,8 @@ function getNextInvalidatedProjectCreateInfo( for (let projectIndex = 0; projectIndex < buildOrder.length; projectIndex++) { const project = buildOrder[projectIndex]; const projectPath = toResolvedConfigFilePath(state, project); - const reloadLevel = state.projectPendingBuild.get(projectPath); - if (reloadLevel === undefined) continue; + const updateLevel = state.projectPendingBuild.get(projectPath); + if (updateLevel === undefined) continue; if (reportQueue) { reportQueue = false; @@ -1417,14 +1417,14 @@ function getNextInvalidatedProjectCreateInfo( continue; } - if (reloadLevel === ConfigFileProgramReloadLevel.Full) { + if (updateLevel === ProgramUpdateLevel.Full) { watchConfigFile(state, project, projectPath, config); watchExtendedConfigFiles(state, projectPath, config); watchWildCardDirectories(state, project, projectPath, config); watchInputFiles(state, project, projectPath, config); watchPackageJsonFiles(state, project, projectPath, config); } - else if (reloadLevel === ConfigFileProgramReloadLevel.Partial) { + else if (updateLevel === ProgramUpdateLevel.RootNamesAndUpdate) { // Update file names config.fileNames = getFileNamesFromConfigSpecs(config.options.configFile!.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost); updateErrorForNoInputFiles(config.fileNames, project, config.options.configFile!.configFileSpecs!, config.errors, canJsonReportNoInputFiles(config.raw)); @@ -2169,7 +2169,7 @@ function queueReferencingProjects( break; } } - addProjToQueue(state, nextProjectPath, ConfigFileProgramReloadLevel.None); + addProjToQueue(state, nextProjectPath, ProgramUpdateLevel.Update); break; } } @@ -2251,7 +2251,7 @@ function cleanWorker(state: SolutionBuilderState, p } else { host.deleteFile(output); - invalidateProject(state, resolvedPath, ConfigFileProgramReloadLevel.None); + invalidateProject(state, resolvedPath, ProgramUpdateLevel.Update); } } } @@ -2264,24 +2264,24 @@ function cleanWorker(state: SolutionBuilderState, p return ExitStatus.Success; } -function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfigFilePath, updateLevel: ProgramUpdateLevel) { // If host implements getParsedCommandLine, we cant get list of files from parseConfigFileHost - if (state.host.getParsedCommandLine && reloadLevel === ConfigFileProgramReloadLevel.Partial) { - reloadLevel = ConfigFileProgramReloadLevel.Full; + if (state.host.getParsedCommandLine && updateLevel === ProgramUpdateLevel.RootNamesAndUpdate) { + updateLevel = ProgramUpdateLevel.Full; } - if (reloadLevel === ConfigFileProgramReloadLevel.Full) { + if (updateLevel === ProgramUpdateLevel.Full) { state.configFileCache.delete(resolved); state.buildOrder = undefined; } state.needsSummary = true; clearProjectStatus(state, resolved); - addProjToQueue(state, resolved, reloadLevel); + addProjToQueue(state, resolved, updateLevel); enableCache(state); } -function invalidateProjectAndScheduleBuilds(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function invalidateProjectAndScheduleBuilds(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, updateLevel: ProgramUpdateLevel) { state.reportFileChangeDetected = true; - invalidateProject(state, resolvedPath, reloadLevel); + invalidateProject(state, resolvedPath, updateLevel); scheduleBuildInvalidatedProject(state, 250, /*changeDetected*/ true); } @@ -2344,7 +2344,7 @@ function watchConfigFile(state: SolutionBuilderState invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Full), + () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.Full), PollingInterval.High, parsed?.watchOptions, WatchType.ConfigFile, @@ -2362,7 +2362,7 @@ function watchExtendedConfigFiles(state: SolutionBuild watchFile( state, extendedConfigFileName, - () => state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach(projectConfigFilePath => invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ConfigFileProgramReloadLevel.Full)), + () => state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach(projectConfigFilePath => invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ProgramUpdateLevel.Full)), PollingInterval.High, parsed?.watchOptions, WatchType.ExtendedConfigFile, @@ -2395,7 +2395,7 @@ function watchWildCardDirectories(state: SolutionBuild }) ) return; - invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Partial); + invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.RootNamesAndUpdate); }, flags, parsed?.watchOptions, @@ -2415,7 +2415,7 @@ function watchInputFiles(state: SolutionBuilderState invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), + () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.Update), PollingInterval.Low, parsed?.watchOptions, WatchType.SourceFile, @@ -2436,7 +2436,7 @@ function watchPackageJsonFiles(state: SolutionBuilderS watchFile( state, path, - () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), + () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.Update), PollingInterval.High, parsed?.watchOptions, WatchType.PackageJson, @@ -2503,7 +2503,7 @@ function createSolutionBuilderWorker(watch: boolean, h const configFilePath = toResolvedConfigFilePath(state, configFileName); return getUpToDateStatus(state, parseConfigFile(state, configFileName, configFilePath), configFilePath); }, - invalidateProject: (configFilePath, reloadLevel) => invalidateProject(state, configFilePath, reloadLevel || ConfigFileProgramReloadLevel.None), + invalidateProject: (configFilePath, updateLevel) => invalidateProject(state, configFilePath, updateLevel || ProgramUpdateLevel.Update), close: () => stopWatching(state), }; } diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index 135c8bdc53887..ac2c666ea8986 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -12,7 +12,6 @@ import { CompilerHost, CompilerOptions, ConfigFileDiagnosticsReporter, - ConfigFileProgramReloadLevel, createBuilderProgramUsingProgramBuildInfo, createCachedDirectoryStructureHost, createCompilerDiagnostic, @@ -64,6 +63,7 @@ import { Path, perfLogger, PollingInterval, + ProgramUpdateLevel, ProjectReference, ResolutionCache, ResolutionCacheHost, @@ -399,8 +399,8 @@ interface ParsedConfig { watcher?: FileWatcher; /** Wild card directories watched from this config file */ watchedDirectories?: Map; - /** Reload to be done for this config file */ - reloadLevel?: ConfigFileProgramReloadLevel.Partial | ConfigFileProgramReloadLevel.Full; + /** Level of program update to be done for this config file */ + updateLevel?: ProgramUpdateLevel.RootNamesAndUpdate | ProgramUpdateLevel.Full; } // All of one and partial of the other, or vice versa. @@ -431,7 +431,7 @@ export function createWatchProgram(host: WatchCompiler type HostFileInfo = FilePresentOnHost | FileMissingOnHost | FilePresenceUnknownOnHost; let builderProgram: T; - let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc + let updateLevel: ProgramUpdateLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc let missingFilesMap: Map; // Map of file watchers for the missing files let watchedWildcardDirectories: Map; // map of watchers for the wild card directories in the config file let timerToUpdateProgram: any; // timer callback to recompile the program @@ -872,7 +872,7 @@ export function createWatchProgram(host: WatchCompiler function scheduleProgramReload() { Debug.assert(!!configFileName); - reloadLevel = ConfigFileProgramReloadLevel.Full; + updateLevel = ProgramUpdateLevel.Full; scheduleProgramUpdate(); } @@ -883,12 +883,12 @@ export function createWatchProgram(host: WatchCompiler } function updateProgram() { - switch (reloadLevel) { - case ConfigFileProgramReloadLevel.Partial: + switch (updateLevel) { + case ProgramUpdateLevel.RootNamesAndUpdate: perfLogger?.logStartUpdateProgram("PartialConfigReload"); reloadFileNamesFromConfigFile(); break; - case ConfigFileProgramReloadLevel.Full: + case ProgramUpdateLevel.Full: perfLogger?.logStartUpdateProgram("FullConfigReload"); reloadConfigFile(); break; @@ -907,7 +907,7 @@ export function createWatchProgram(host: WatchCompiler Debug.assert(compilerOptions); Debug.assert(configFileName); - reloadLevel = ConfigFileProgramReloadLevel.None; + updateLevel = ProgramUpdateLevel.Update; rootFileNames = getFileNamesFromConfigSpecs(compilerOptions.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions); if (updateErrorForNoInputFiles(rootFileNames, getNormalizedAbsolutePath(configFileName, currentDirectory), compilerOptions.configFile!.configFileSpecs!, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) { hasChangedConfigFileParsingErrors = true; @@ -920,7 +920,7 @@ export function createWatchProgram(host: WatchCompiler function reloadConfigFile() { Debug.assert(configFileName); writeLog(`Reloading config file: ${configFileName}`); - reloadLevel = ConfigFileProgramReloadLevel.None; + updateLevel = ProgramUpdateLevel.Update; if (cachedDirectoryStructureHost) { cachedDirectoryStructureHost.clearCache(); @@ -965,9 +965,9 @@ export function createWatchProgram(host: WatchCompiler const configPath = toPath(configFileName); let config = parsedConfigs?.get(configPath); if (config) { - if (!config.reloadLevel) return config.parsedCommandLine; + if (!config.updateLevel) return config.parsedCommandLine; // With host implementing getParsedCommandLine we cant just update file names - if (config.parsedCommandLine && config.reloadLevel === ConfigFileProgramReloadLevel.Partial && !host.getParsedCommandLine) { + if (config.parsedCommandLine && config.updateLevel === ProgramUpdateLevel.RootNamesAndUpdate && !host.getParsedCommandLine) { writeLog("Reloading new file names and options"); Debug.assert(compilerOptions); const fileNames = getFileNamesFromConfigSpecs( @@ -977,7 +977,7 @@ export function createWatchProgram(host: WatchCompiler parseConfigFileHost, ); config.parsedCommandLine = { ...config.parsedCommandLine, fileNames }; - config.reloadLevel = undefined; + config.updateLevel = undefined; return config.parsedCommandLine; } } @@ -988,7 +988,7 @@ export function createWatchProgram(host: WatchCompiler getParsedCommandLineFromConfigFileHost(configFileName); if (config) { config.parsedCommandLine = parsedCommandLine; - config.reloadLevel = undefined; + config.updateLevel = undefined; } else { (parsedConfigs ||= new Map()).set(configPath, config = { parsedCommandLine }); @@ -1120,8 +1120,8 @@ export function createWatchProgram(host: WatchCompiler ) return; // Reload is pending, do the reload - if (reloadLevel !== ConfigFileProgramReloadLevel.Full) { - reloadLevel = ConfigFileProgramReloadLevel.Partial; + if (updateLevel !== ProgramUpdateLevel.Full) { + updateLevel = ProgramUpdateLevel.RootNamesAndUpdate; // Schedule Update the program scheduleProgramUpdate(); @@ -1152,12 +1152,12 @@ export function createWatchProgram(host: WatchCompiler projects.forEach(projectPath => { if (configFileName && toPath(configFileName) === projectPath) { // If this is the config file of the project, reload completely - reloadLevel = ConfigFileProgramReloadLevel.Full; + updateLevel = ProgramUpdateLevel.Full; } else { // Reload config for the referenced projects and remove the resolutions from referenced projects since the config file changed const config = parsedConfigs?.get(projectPath); - if (config) config.reloadLevel = ConfigFileProgramReloadLevel.Full; + if (config) config.updateLevel = ProgramUpdateLevel.Full; resolutionCache.removeResolutionsFromProjectReferenceRedirects(projectPath); } scheduleProgramUpdate(); @@ -1178,7 +1178,7 @@ export function createWatchProgram(host: WatchCompiler (_fileName, eventKind) => { updateCachedSystemWithFile(configFileName, configPath, eventKind); const config = parsedConfigs?.get(configPath); - if (config) config.reloadLevel = ConfigFileProgramReloadLevel.Full; + if (config) config.updateLevel = ProgramUpdateLevel.Full; resolutionCache.removeResolutionsFromProjectReferenceRedirects(configPath); scheduleProgramUpdate(); }, @@ -1220,8 +1220,8 @@ export function createWatchProgram(host: WatchCompiler ) return; // Reload is pending, do the reload - if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) { - config.reloadLevel = ConfigFileProgramReloadLevel.Partial; + if (config.updateLevel !== ProgramUpdateLevel.Full) { + config.updateLevel = ProgramUpdateLevel.RootNamesAndUpdate; // Schedule Update the program scheduleProgramUpdate(); diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts index 422ec2f70be4c..c259f2ac9db95 100644 --- a/src/compiler/watchUtilities.ts +++ b/src/compiler/watchUtilities.ts @@ -365,12 +365,18 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, } } -/** @internal */ -export enum ConfigFileProgramReloadLevel { - None, - /** Update the file name list from the disk */ - Partial, - /** Reload completely by re-reading contents of config file from disk and updating program */ +export enum ProgramUpdateLevel { + /** Program is updated with same root file names and options */ + Update, + /** Loads program after updating root file names from the disk */ + RootNamesAndUpdate, + /** + * Loads program completely, including: + * - re-reading contents of config file from disk + * - calculating root file names for the program + * - Updating the program + */ + Full, } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 9f3da93b674c8..976ce0a27cb38 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -14,7 +14,6 @@ import { CommandLineOption, CompilerOptions, CompletionInfo, - ConfigFileProgramReloadLevel, contains, containsPath, convertCompilerOptionsForTelemetry, @@ -95,6 +94,7 @@ import { PerformanceEvent, PluginImport, PollingInterval, + ProgramUpdateLevel, ProjectPackageJsonInfo, ProjectReference, ReadMapFile, @@ -874,7 +874,7 @@ export interface ParsedConfig { * true if watchedDirectories need to be updated as per parsedCommandLine's updated watched directories */ watchedDirectoriesStale?: boolean; - reloadLevel?: ConfigFileProgramReloadLevel.Partial | ConfigFileProgramReloadLevel.Full; + updateLevel?: ProgramUpdateLevel.RootNamesAndUpdate | ProgramUpdateLevel.Full; } function createProjectNameFactoryWithCounter(nameFactory: (counter: number) => string) { @@ -1671,7 +1671,7 @@ export class ProjectService { ) return; // Reload is pending, do the reload - if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) config.reloadLevel = ConfigFileProgramReloadLevel.Partial; + if (config.updateLevel !== ProgramUpdateLevel.Full) config.updateLevel = ProgramUpdateLevel.RootNamesAndUpdate; config.projects.forEach((watchWildcardDirectories, projectCanonicalPath) => { if (!watchWildcardDirectories) return; const project = this.getConfiguredProjectByCanonicalConfigFilePath(projectCanonicalPath); @@ -1679,23 +1679,23 @@ export class ProjectService { // Load root file names for configured project with the config file name // But only schedule update if project references this config file - const reloadLevel = configuredProjectForConfig === project ? ConfigFileProgramReloadLevel.Partial : ConfigFileProgramReloadLevel.None; - if (project.pendingReload !== undefined && project.pendingReload > reloadLevel) return; + const updateLevel = configuredProjectForConfig === project ? ProgramUpdateLevel.RootNamesAndUpdate : ProgramUpdateLevel.Update; + if (project.pendingUpdateLevel !== undefined && project.pendingUpdateLevel > updateLevel) return; // don't trigger callback on open, existing files if (this.openFiles.has(fileOrDirectoryPath)) { const info = Debug.checkDefined(this.getScriptInfoForPath(fileOrDirectoryPath)); if (info.isAttached(project)) { - const loadLevelToSet = Math.max(reloadLevel, project.openFileWatchTriggered.get(fileOrDirectoryPath) || ConfigFileProgramReloadLevel.None) as ConfigFileProgramReloadLevel; + const loadLevelToSet = Math.max(updateLevel, project.openFileWatchTriggered.get(fileOrDirectoryPath) || ProgramUpdateLevel.Update) as ProgramUpdateLevel; project.openFileWatchTriggered.set(fileOrDirectoryPath, loadLevelToSet); } else { - project.pendingReload = reloadLevel; + project.pendingUpdateLevel = updateLevel; this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project); } } else { - project.pendingReload = reloadLevel; + project.pendingUpdateLevel = updateLevel; this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project); } }); @@ -1708,12 +1708,12 @@ export class ProjectService { } /** @internal */ - private delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalConfigFilePath: NormalizedPath, reloadReason: string) { + private delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalConfigFilePath: NormalizedPath, loadReason: string) { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (!configFileExistenceInfo?.config) return false; let scheduledAnyProjectUpdate = false; // Update projects watching cached config - configFileExistenceInfo.config.reloadLevel = ConfigFileProgramReloadLevel.Full; + configFileExistenceInfo.config.updateLevel = ProgramUpdateLevel.Full; configFileExistenceInfo.config.projects.forEach((_watchWildcardDirectories, projectCanonicalPath) => { const project = this.getConfiguredProjectByCanonicalConfigFilePath(projectCanonicalPath); @@ -1723,8 +1723,8 @@ export class ProjectService { if (projectCanonicalPath === canonicalConfigFilePath) { // Skip refresh if project is not yet loaded if (project.isInitialLoadPending()) return; - project.pendingReload = ConfigFileProgramReloadLevel.Full; - project.pendingReloadReason = reloadReason; + project.pendingUpdateLevel = ProgramUpdateLevel.Full; + project.pendingUpdateReason = loadReason; this.delayUpdateProjectGraph(project); } else { @@ -1922,11 +1922,11 @@ export class ProjectService { // If project had open file affecting // Reload the root Files from config if its not already scheduled - const reloadLevel = p.openFileWatchTriggered.get(info.path); - if (reloadLevel !== undefined) { + const updateLevel = p.openFileWatchTriggered.get(info.path); + if (updateLevel !== undefined) { p.openFileWatchTriggered.delete(info.path); - if (p.pendingReload !== undefined && p.pendingReload < reloadLevel) { - p.pendingReload = reloadLevel; + if (p.pendingUpdateLevel !== undefined && p.pendingUpdateLevel < updateLevel) { + p.pendingUpdateLevel = updateLevel; p.markFileAsDirty(info.path); } } @@ -2438,7 +2438,7 @@ export class ProjectService { configFileExistenceInfo.config = { cachedDirectoryStructureHost: createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames)!, projects: new Map(), - reloadLevel: ConfigFileProgramReloadLevel.Full, + updateLevel: ProgramUpdateLevel.Full, }; } @@ -2457,8 +2457,8 @@ export class ProjectService { /** @internal */ private createConfiguredProjectWithDelayLoad(configFileName: NormalizedPath, reason: string) { const project = this.createConfiguredProject(configFileName); - project.pendingReload = ConfigFileProgramReloadLevel.Full; - project.pendingReloadReason = reason; + project.pendingUpdateLevel = ProgramUpdateLevel.Full; + project.pendingUpdateReason = reason; return project; } @@ -2521,7 +2521,7 @@ export class ProjectService { this.watchWildcards(configFilename, configFileExistenceInfo, project); } project.enablePluginsWithOptions(compilerOptions); - const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles()); + const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles(ProgramUpdateLevel.Full)); this.updateRootAndOptionsOfNonInferredProject(project, filesToAdd, fileNamePropertyReader, compilerOptions, parsedCommandLine.typeAcquisition!, parsedCommandLine.compileOnSave, parsedCommandLine.watchOptions); tracing?.pop(); } @@ -2529,8 +2529,8 @@ export class ProjectService { /** @internal */ ensureParsedConfigUptoDate(configFilename: NormalizedPath, canonicalConfigFilePath: NormalizedPath, configFileExistenceInfo: ConfigFileExistenceInfo, forProject: ConfiguredProject): ConfigFileExistenceInfo { if (configFileExistenceInfo.config) { - if (!configFileExistenceInfo.config.reloadLevel) return configFileExistenceInfo; - if (configFileExistenceInfo.config.reloadLevel === ConfigFileProgramReloadLevel.Partial) { + if (!configFileExistenceInfo.config.updateLevel) return configFileExistenceInfo; + if (configFileExistenceInfo.config.updateLevel === ProgramUpdateLevel.RootNamesAndUpdate) { this.reloadFileNamesOfParsedConfig(configFilename, configFileExistenceInfo.config); return configFileExistenceInfo; } @@ -2580,7 +2580,7 @@ export class ProjectService { else { configFileExistenceInfo.config.parsedCommandLine = parsedCommandLine; configFileExistenceInfo.config.watchedDirectoriesStale = true; - configFileExistenceInfo.config.reloadLevel = undefined; + configFileExistenceInfo.config.updateLevel = undefined; } // If watch options different than older options when setting for the first time, update the config file watcher @@ -2761,14 +2761,14 @@ export class ProjectService { reloadFileNamesOfConfiguredProject(project: ConfiguredProject) { const fileNames = this.reloadFileNamesOfParsedConfig(project.getConfigFilePath(), this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!.config!); project.updateErrorOnNoInputFiles(fileNames); - this.updateNonInferredProjectFiles(project, fileNames.concat(project.getExternalFiles()), fileNamePropertyReader); + this.updateNonInferredProjectFiles(project, fileNames.concat(project.getExternalFiles(ProgramUpdateLevel.RootNamesAndUpdate)), fileNamePropertyReader); return project.updateGraph(); } /** @internal */ private reloadFileNamesOfParsedConfig(configFileName: NormalizedPath, config: ParsedConfig) { - if (config.reloadLevel === undefined) return config.parsedCommandLine!.fileNames; - Debug.assert(config.reloadLevel === ConfigFileProgramReloadLevel.Partial); + if (config.updateLevel === undefined) return config.parsedCommandLine!.fileNames; + Debug.assert(config.updateLevel === ProgramUpdateLevel.RootNamesAndUpdate); const configFileSpecs = config.parsedCommandLine!.options.configFile!.configFileSpecs!; const fileNames = getFileNamesFromConfigSpecs( configFileSpecs, @@ -3398,7 +3398,7 @@ export class ProjectService { this.configuredProjects.forEach(project => { if ( project.hasExternalProjectRef() && - project.pendingReload === ConfigFileProgramReloadLevel.Full && + project.pendingUpdateLevel === ProgramUpdateLevel.Full && !this.pendingProjectUpdates.has(project.getProjectName()) ) { project.updateGraph(); @@ -3468,7 +3468,7 @@ export class ProjectService { // Ensure everything is reloaded for cached configs this.configFileExistenceInfoCache.forEach(info => { - if (info.config) info.config.reloadLevel = ConfigFileProgramReloadLevel.Full; + if (info.config) info.config.updateLevel = ProgramUpdateLevel.Full; }); // Reload Projects @@ -3517,8 +3517,8 @@ export class ProjectService { if (!updatedProjects.has(project.canonicalConfigFilePath)) { updatedProjects.set(project.canonicalConfigFilePath, true); if (delayReload) { - project.pendingReload = ConfigFileProgramReloadLevel.Full; - project.pendingReloadReason = reason; + project.pendingUpdateLevel = ProgramUpdateLevel.Full; + project.pendingUpdateReason = reason; if (clearSemanticCache) this.clearSemanticCache(project); this.delayUpdateProjectGraph(project); } diff --git a/src/server/project.ts b/src/server/project.ts index 8bffa1f281a86..5293e06fa540b 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -17,7 +17,6 @@ import { CompilerHost, CompilerOptions, concatenate, - ConfigFileProgramReloadLevel, containsPath, createCacheableExportInfoMap, createLanguageService, @@ -98,6 +97,7 @@ import { PluginImport, PollingInterval, Program, + ProgramUpdateLevel, ProjectPackageJsonInfo, ProjectReference, removeFileExtension, @@ -254,7 +254,7 @@ export interface PluginCreateInfo { export interface PluginModule { create(createInfo: PluginCreateInfo): LanguageService; - getExternalFiles?(proj: Project): string[]; + getExternalFiles?(proj: Project, updateLevel: ProgramUpdateLevel): string[]; onConfigurationChanged?(config: any): void; } @@ -1027,11 +1027,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return { ...newTypeAcquisition, include: this.removeExistingTypings(newTypeAcquisition.include) }; } - getExternalFiles(): SortedReadonlyArray { + getExternalFiles(updateLevel?: ProgramUpdateLevel): SortedReadonlyArray { return sort(flatMap(this.plugins, plugin => { if (typeof plugin.module.getExternalFiles !== "function") return; try { - return plugin.module.getExternalFiles(this); + return plugin.module.getExternalFiles(this, updateLevel || ProgramUpdateLevel.Update); } catch (e) { this.projectService.logger.info(`A plugin threw an exception in getExternalFiles: ${e}`); @@ -1892,10 +1892,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } // compute and return the difference const lastReportedFileNames = this.lastReportedFileNames; - const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ + const externalFiles = this.externalFiles?.map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName: toNormalizedPath(f), isSourceOfProjectReferenceRedirect: false, - })); + })) || emptyArray; const currentFiles = arrayToMap( this.getFileNamesWithRedirectInfo(!!includeProjectReferenceRedirectInfo).concat(externalFiles), info => info.fileName, @@ -1945,10 +1945,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo else { // unknown version - return everything const projectFileNames = this.getFileNamesWithRedirectInfo(!!includeProjectReferenceRedirectInfo); - const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ + const externalFiles = this.externalFiles?.map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName: toNormalizedPath(f), isSourceOfProjectReferenceRedirect: false, - })); + })) || emptyArray; const allFiles = projectFileNames.concat(externalFiles); this.lastReportedFileNames = arrayToMap( allFiles, @@ -2679,12 +2679,12 @@ export class AutoImportProviderProject extends Project { */ export class ConfiguredProject extends Project { /** @internal */ - pendingReload: ConfigFileProgramReloadLevel | undefined; + pendingUpdateLevel: ProgramUpdateLevel | undefined; /** @internal */ - pendingReloadReason: string | undefined; + pendingUpdateReason: string | undefined; /** @internal */ - openFileWatchTriggered = new Map(); + openFileWatchTriggered = new Map(); /** @internal */ canConfigFileJsonReportNoInputFiles = false; @@ -2775,18 +2775,18 @@ export class ConfiguredProject extends Project { override updateGraph(): boolean { const isInitialLoad = this.isInitialLoadPending(); this.isInitialLoadPending = returnFalse; - const reloadLevel = this.pendingReload; - this.pendingReload = ConfigFileProgramReloadLevel.None; + const updateLevel = this.pendingUpdateLevel; + this.pendingUpdateLevel = ProgramUpdateLevel.Update; let result: boolean; - switch (reloadLevel) { - case ConfigFileProgramReloadLevel.Partial: + switch (updateLevel) { + case ProgramUpdateLevel.RootNamesAndUpdate: this.openFileWatchTriggered.clear(); result = this.projectService.reloadFileNamesOfConfiguredProject(this); break; - case ConfigFileProgramReloadLevel.Full: + case ProgramUpdateLevel.Full: this.openFileWatchTriggered.clear(); - const reason = Debug.checkDefined(this.pendingReloadReason); - this.pendingReloadReason = undefined; + const reason = Debug.checkDefined(this.pendingUpdateReason); + this.pendingUpdateReason = undefined; this.projectService.reloadConfiguredProject(this, reason, isInitialLoad, /*clearSemanticCache*/ false); result = true; break; diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index 5c6727ba5310d..62653cd49a235 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -685,10 +685,10 @@ describe("unittests:: tsserver:: externalProjects", () => { options: {}, } as ts.server.protocol.ExternalProject); const project = service.configuredProjects.get(config.path)!; - assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded + assert.equal(project.pendingUpdateLevel, ts.ProgramUpdateLevel.Full); // External project referenced configured project pending to be reloaded service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: false } }); - assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded + assert.equal(project.pendingUpdateLevel, ts.ProgramUpdateLevel.Update); // External project referenced configured project loaded service.closeExternalProject(projectFileName); @@ -698,7 +698,7 @@ describe("unittests:: tsserver:: externalProjects", () => { options: {}, } as ts.server.protocol.ExternalProject); const project2 = service.configuredProjects.get(config.path)!; - assert.equal(project2.pendingReload, ts.ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded + assert.equal(project2.pendingUpdateLevel, ts.ProgramUpdateLevel.Update); // External project referenced configured project loaded baselineTsserverLogs("externalProjects", "handles loads existing configured projects of external projects when lazyConfiguredProjectsFromExternalProject is disabled", service); }); diff --git a/src/testRunner/unittests/tsserver/plugins.ts b/src/testRunner/unittests/tsserver/plugins.ts index bcc1add3b9706..c73f12b987d76 100644 --- a/src/testRunner/unittests/tsserver/plugins.ts +++ b/src/testRunner/unittests/tsserver/plugins.ts @@ -225,6 +225,10 @@ describe("unittests:: tsserver:: plugins:: supportedExtensions::", () => { path: "/user/username/projects/myproject/a.ts", content: `export const a = 10;`, }; + const dTs: File = { + path: "/user/username/projects/myproject/d.ts", + content: `export const d = 10;`, + }; const bVue: File = { path: "/user/username/projects/myproject/b.vue", content: "bVue file", @@ -240,7 +244,8 @@ describe("unittests:: tsserver:: plugins:: supportedExtensions::", () => { " ", ), }; - const host = createServerHost([aTs, bVue, config, libFile]); + const host = createServerHost([aTs, dTs, bVue, config, libFile]); + const externalFiles = new Map(); host.require = () => { return { module: () => ({ @@ -258,8 +263,16 @@ describe("unittests:: tsserver:: plugins:: supportedExtensions::", () => { originalGetScriptSnapshot(fileName); return proxy; }, - getExternalFiles: (project: ts.server.Project) => { + getExternalFiles: (project: ts.server.Project, updateLevel: ts.ProgramUpdateLevel) => { if (project.projectKind !== ts.server.ProjectKind.Configured) return []; + if (updateLevel === ts.ProgramUpdateLevel.Update) { + const existing = externalFiles.get(project); + if (existing) { + session.logger.log(`getExternalFiles:: Returning cached .vue files`); + return existing; + } + } + session.logger.log(`getExternalFiles:: Getting new list of .vue files`); const configFile = project.getProjectName(); const config = ts.readJsonConfigFile(configFile, project.readFile.bind(project)); const parseHost: ts.ParseConfigHost = { @@ -272,6 +285,7 @@ describe("unittests:: tsserver:: plugins:: supportedExtensions::", () => { }, }; const parsed = ts.parseJsonSourceFileConfigFileContent(config, parseHost, project.getCurrentDirectory()); + externalFiles.set(project, parsed.fileNames); return parsed.fileNames; }, }), @@ -284,6 +298,9 @@ describe("unittests:: tsserver:: plugins:: supportedExtensions::", () => { host.writeFile("/user/username/projects/myproject/c.vue", "cVue file"); host.runQueuedTimeoutCallbacks(); + host.appendFile(dTs.path, "export const x = 10;"); + host.runQueuedTimeoutCallbacks(); + baselineTsserverLogs("plugins", "new files with non ts extensions with wildcard matching", session); }); }); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 00e41bf46de3f..4b783a4b8dca4 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3274,7 +3274,7 @@ declare namespace ts { } interface PluginModule { create(createInfo: PluginCreateInfo): LanguageService; - getExternalFiles?(proj: Project): string[]; + getExternalFiles?(proj: Project, updateLevel: ProgramUpdateLevel): string[]; onConfigurationChanged?(config: any): void; } interface PluginModuleWithName { @@ -3379,7 +3379,7 @@ declare namespace ts { disableLanguageService(lastFileExceededProgramSize?: string): void; getProjectName(): string; protected removeLocalTypingsFromTypeAcquisition(newTypeAcquisition: TypeAcquisition): TypeAcquisition; - getExternalFiles(): SortedReadonlyArray; + getExternalFiles(updateLevel?: ProgramUpdateLevel): SortedReadonlyArray; getSourceFile(path: Path): ts.SourceFile | undefined; close(): void; private detachScriptInfoIfNotRoot; @@ -9829,6 +9829,19 @@ declare namespace ts { function getTsBuildInfoEmitOutputFilePath(options: CompilerOptions): string | undefined; function getOutputFileNames(commandLine: ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[]; function createPrinter(printerOptions?: PrinterOptions, handlers?: PrintHandlers): Printer; + enum ProgramUpdateLevel { + /** Program is updated with same root file names and options */ + Update = 0, + /** Loads program after updating root file names from the disk */ + RootNamesAndUpdate = 1, + /** + * Loads program completely, including: + * - re-reading contents of config file from disk + * - calculating root file names for the program + * - Updating the program + */ + Full = 2, + } function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName?: string): string | undefined; function resolveTripleslashReference(moduleName: string, containingFile: string): string; function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost; diff --git a/tests/baselines/reference/tsserver/plugins/new-files-with-non-ts-extensions-with-wildcard-matching.js b/tests/baselines/reference/tsserver/plugins/new-files-with-non-ts-extensions-with-wildcard-matching.js index d8ff142f2819c..891fc361e9f8d 100644 --- a/tests/baselines/reference/tsserver/plugins/new-files-with-non-ts-extensions-with-wildcard-matching.js +++ b/tests/baselines/reference/tsserver/plugins/new-files-with-non-ts-extensions-with-wildcard-matching.js @@ -4,6 +4,9 @@ Before request //// [/user/username/projects/myproject/a.ts] export const a = 10; +//// [/user/username/projects/myproject/d.ts] +export const d = 10; + //// [/user/username/projects/myproject/b.vue] bVue file @@ -47,7 +50,8 @@ Info seq [hh:mm:ss:mss] Creating configuration project /user/username/projects/ Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/tsconfig.json 2000 undefined Project: /user/username/projects/myproject/tsconfig.json WatchType: Config file Info seq [hh:mm:ss:mss] Config: /user/username/projects/myproject/tsconfig.json : { "rootNames": [ - "/user/username/projects/myproject/a.ts" + "/user/username/projects/myproject/a.ts", + "/user/username/projects/myproject/d.ts" ], "options": { "composite": true, @@ -60,6 +64,8 @@ Info seq [hh:mm:ss:mss] Loading global plugin myplugin Info seq [hh:mm:ss:mss] Enabling plugin myplugin from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Loading myplugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) Info seq [hh:mm:ss:mss] Plugin validation succeeded +getExternalFiles:: Getting new list of .vue files +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/b.vue 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /user/username/projects/myproject/tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info @@ -67,11 +73,13 @@ Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/username/pr Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/node_modules/@types 1 undefined Project: /user/username/projects/myproject/tsconfig.json WatchType: Type roots Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/node_modules/@types 1 undefined Project: /user/username/projects/myproject/tsconfig.json WatchType: Type roots Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/node_modules/@types 1 undefined Project: /user/username/projects/myproject/tsconfig.json WatchType: Type roots +getExternalFiles:: Returning cached .vue files Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /user/username/projects/myproject/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (3) +Info seq [hh:mm:ss:mss] Files (4) /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" /user/username/projects/myproject/a.ts SVC-1-0 "export const a = 10;" + /user/username/projects/myproject/d.ts Text-1 "export const d = 10;" /user/username/projects/myproject/b.vue Text-1 "export const y = \"bVue file\";" @@ -79,6 +87,8 @@ Info seq [hh:mm:ss:mss] Files (3) Default library for target 'es5' a.ts Matched by include pattern '*.ts' in 'tsconfig.json' + d.ts + Matched by include pattern '*.ts' in 'tsconfig.json' b.vue Matched by include pattern '*.vue' in 'tsconfig.json' @@ -86,7 +96,7 @@ Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Search path: /user/username/projects/myproject Info seq [hh:mm:ss:mss] For info: /user/username/projects/myproject/tsconfig.json :: No config files found. Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (3) +Info seq [hh:mm:ss:mss] Files (4) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Open files: @@ -111,6 +121,8 @@ FsWatches:: {} /user/username/projects/myproject/b.vue: *new* {} +/user/username/projects/myproject/d.ts: *new* + {} /user/username/projects/myproject/tsconfig.json: *new* {} @@ -126,13 +138,16 @@ cVue file Info seq [hh:mm:ss:mss] Running: /user/username/projects/myproject/tsconfig.json +getExternalFiles:: Getting new list of .vue files Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/c.vue 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /user/username/projects/myproject/tsconfig.json +getExternalFiles:: Returning cached .vue files Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /user/username/projects/myproject/tsconfig.json Version: 2 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (4) +Info seq [hh:mm:ss:mss] Files (5) /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" /user/username/projects/myproject/a.ts SVC-1-0 "export const a = 10;" + /user/username/projects/myproject/d.ts Text-1 "export const d = 10;" /user/username/projects/myproject/b.vue Text-1 "export const y = \"bVue file\";" /user/username/projects/myproject/c.vue Text-1 "export const y = \"cVue file\";" @@ -141,6 +156,8 @@ Info seq [hh:mm:ss:mss] Files (4) Default library for target 'es5' a.ts Matched by include pattern '*.ts' in 'tsconfig.json' + d.ts + Matched by include pattern '*.ts' in 'tsconfig.json' b.vue Matched by include pattern '*.vue' in 'tsconfig.json' c.vue @@ -150,7 +167,7 @@ Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Running: *ensureProjectForOpenFiles* Info seq [hh:mm:ss:mss] Before ensureProjectForOpenFiles: Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (4) +Info seq [hh:mm:ss:mss] Files (5) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Open files: @@ -158,7 +175,7 @@ Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/a.ts Proje Info seq [hh:mm:ss:mss] Projects: /user/username/projects/myproject/tsconfig.json Info seq [hh:mm:ss:mss] After ensureProjectForOpenFiles: Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (4) +Info seq [hh:mm:ss:mss] Files (5) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Open files: @@ -181,5 +198,50 @@ FsWatches:: {} /user/username/projects/myproject/c.vue: *new* {} +/user/username/projects/myproject/d.ts: + {} /user/username/projects/myproject/tsconfig.json: {} + +Info seq [hh:mm:ss:mss] FileWatcher:: Triggered with /user/username/projects/myproject/d.ts 1:: WatchInfo: /user/username/projects/myproject/d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Scheduled: /user/username/projects/myproject/tsconfig.json +Info seq [hh:mm:ss:mss] Scheduled: *ensureProjectForOpenFiles* +Info seq [hh:mm:ss:mss] Elapsed:: *ms FileWatcher:: Triggered with /user/username/projects/myproject/d.ts 1:: WatchInfo: /user/username/projects/myproject/d.ts 500 undefined WatchType: Closed Script info +Before running Timeout callback:: count: 2 +3: /user/username/projects/myproject/tsconfig.json +4: *ensureProjectForOpenFiles* +//// [/user/username/projects/myproject/d.ts] +export const d = 10;export const x = 10; + + +Info seq [hh:mm:ss:mss] Running: /user/username/projects/myproject/tsconfig.json +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /user/username/projects/myproject/tsconfig.json +getExternalFiles:: Returning cached .vue files +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /user/username/projects/myproject/tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + /user/username/projects/myproject/a.ts SVC-1-0 "export const a = 10;" + /user/username/projects/myproject/d.ts Text-2 "export const d = 10;export const x = 10;" + /user/username/projects/myproject/b.vue Text-1 "export const y = \"bVue file\";" + /user/username/projects/myproject/c.vue Text-1 "export const y = \"cVue file\";" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Running: *ensureProjectForOpenFiles* +Info seq [hh:mm:ss:mss] Before ensureProjectForOpenFiles: +Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/a.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /user/username/projects/myproject/tsconfig.json +Info seq [hh:mm:ss:mss] After ensureProjectForOpenFiles: +Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/a.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /user/username/projects/myproject/tsconfig.json +After running Timeout callback:: count: 0 From 08d6df0813e9a2227afb26721e1f64ef0a402f6e Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Tue, 10 Oct 2023 06:19:41 +0000 Subject: [PATCH 7/7] Update package-lock.json --- package-lock.json | 214 +++++++++++++++++++++++++--------------------- 1 file changed, 116 insertions(+), 98 deletions(-) diff --git a/package-lock.json b/package-lock.json index facac0374d15e..decca6968368a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -880,9 +880,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-/k+vesl92vMvMygmQrFe9Aimxi6oQXFUX9mA5HanTrKUSAMoLauSi6PNFOdRw0oeqilaW600GNx2vSaT2f8aIQ==", "dev": true }, "node_modules/@types/glob": { @@ -938,10 +938,13 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", - "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==", - "dev": true + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.4.tgz", + "integrity": "sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==", + "dev": true, + "dependencies": { + "undici-types": "~5.25.1" + } }, "node_modules/@types/semver": { "version": "7.5.3", @@ -965,16 +968,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz", - "integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", + "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/type-utils": "6.7.4", - "@typescript-eslint/utils": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1000,15 +1003,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz", - "integrity": "sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz", + "integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4" }, "engines": { @@ -1028,13 +1031,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz", - "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1045,13 +1048,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz", - "integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", + "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1072,9 +1075,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz", - "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1085,13 +1088,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz", - "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1112,17 +1115,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz", - "integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", + "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", "semver": "^7.5.4" }, "engines": { @@ -1137,12 +1140,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz", - "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3729,6 +3732,12 @@ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, "node_modules/universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", @@ -4410,9 +4419,9 @@ } }, "@types/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-/k+vesl92vMvMygmQrFe9Aimxi6oQXFUX9mA5HanTrKUSAMoLauSi6PNFOdRw0oeqilaW600GNx2vSaT2f8aIQ==", "dev": true }, "@types/glob": { @@ -4468,10 +4477,13 @@ "dev": true }, "@types/node": { - "version": "20.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", - "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==", - "dev": true + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.4.tgz", + "integrity": "sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==", + "dev": true, + "requires": { + "undici-types": "~5.25.1" + } }, "@types/semver": { "version": "7.5.3", @@ -4495,16 +4507,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz", - "integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", + "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/type-utils": "6.7.4", - "@typescript-eslint/utils": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -4514,54 +4526,54 @@ } }, "@typescript-eslint/parser": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz", - "integrity": "sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz", + "integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz", - "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "requires": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" } }, "@typescript-eslint/type-utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz", - "integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", + "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz", - "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz", - "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "requires": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4570,27 +4582,27 @@ } }, "@typescript-eslint/utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz", - "integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", + "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz", - "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "requires": { - "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" } }, @@ -6448,6 +6460,12 @@ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, + "undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",