Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internal/checker/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -2405,7 +2405,7 @@ func (c *Checker) typeMaybeAssignableTo(source *Type, target *Type) bool {
func (c *Checker) getTypePredicateArgument(predicate *TypePredicate, callExpression *ast.Node) *ast.Node {
if predicate.kind == TypePredicateKindIdentifier || predicate.kind == TypePredicateKindAssertsIdentifier {
arguments := callExpression.Arguments()
if int(predicate.parameterIndex) < len(arguments) {
if predicate.parameterIndex >= 0 && int(predicate.parameterIndex) < len(arguments) {
return arguments[predicate.parameterIndex]
}
} else {
Expand Down Expand Up @@ -2496,7 +2496,7 @@ func (c *Checker) isReachableFlowNodeWorker(f *FlowState, flow *ast.FlowNode, no
case flags&ast.FlowFlagsCall != 0:
if signature := c.getEffectsSignature(flow.Node); signature != nil {
if predicate := c.getTypePredicateOfSignature(signature); predicate != nil && predicate.kind == TypePredicateKindAssertsIdentifier && predicate.t == nil {
if arguments := flow.Node.Arguments(); int(predicate.parameterIndex) < len(arguments) && c.isFalseExpression(arguments[predicate.parameterIndex]) {
if arguments := flow.Node.Arguments(); predicate.parameterIndex >= 0 && int(predicate.parameterIndex) < len(arguments) && c.isFalseExpression(arguments[predicate.parameterIndex]) {
return false
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
assertsPredicateParameterMismatch.ts(7,12): error TS1225: Cannot find parameter 'condition'.


==== assertsPredicateParameterMismatch.ts (1 errors) ====
// This test verifies that the checker doesn't panic when an assertion predicate
// references a parameter name that doesn't match any actual function parameter.
// This specifically tests the code path in isReachableFlowNodeWorker.

function assertCondition(
_condition: boolean
): asserts condition { // "condition" doesn't match parameter "_condition"
~~~~~~~~~
!!! error TS1225: Cannot find parameter 'condition'.
if (!_condition) {
throw new Error('Condition failed');
}
}

function test(): void {
assertCondition(false);
console.log("unreachable");
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/compiler/assertsPredicateParameterMismatch.ts] ////

=== assertsPredicateParameterMismatch.ts ===
// This test verifies that the checker doesn't panic when an assertion predicate
// references a parameter name that doesn't match any actual function parameter.
// This specifically tests the code path in isReachableFlowNodeWorker.

function assertCondition(
>assertCondition : Symbol(assertCondition, Decl(assertsPredicateParameterMismatch.ts, 0, 0))

_condition: boolean
>_condition : Symbol(_condition, Decl(assertsPredicateParameterMismatch.ts, 4, 25))

): asserts condition { // "condition" doesn't match parameter "_condition"
if (!_condition) {
>_condition : Symbol(_condition, Decl(assertsPredicateParameterMismatch.ts, 4, 25))

throw new Error('Condition failed');
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
}
}

function test(): void {
>test : Symbol(test, Decl(assertsPredicateParameterMismatch.ts, 10, 1))

assertCondition(false);
>assertCondition : Symbol(assertCondition, Decl(assertsPredicateParameterMismatch.ts, 0, 0))

console.log("unreachable");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//// [tests/cases/compiler/assertsPredicateParameterMismatch.ts] ////

=== assertsPredicateParameterMismatch.ts ===
// This test verifies that the checker doesn't panic when an assertion predicate
// references a parameter name that doesn't match any actual function parameter.
// This specifically tests the code path in isReachableFlowNodeWorker.

function assertCondition(
>assertCondition : (_condition: boolean) => asserts condition

_condition: boolean
>_condition : boolean

): asserts condition { // "condition" doesn't match parameter "_condition"
if (!_condition) {
>!_condition : boolean
>_condition : boolean

throw new Error('Condition failed');
>new Error('Condition failed') : Error
>Error : ErrorConstructor
>'Condition failed' : "Condition failed"
}
}

function test(): void {
>test : () => void

assertCondition(false);
>assertCondition(false) : void
>assertCondition : (_condition: boolean) => asserts condition
>false : false

console.log("unreachable");
>console.log("unreachable") : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>"unreachable" : "unreachable"
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
typePredicateParameterMismatch.ts(10,4): error TS1225: Cannot find parameter 'value'.


==== typePredicateParameterMismatch.ts (1 errors) ====
// This test verifies that the checker doesn't panic when a type predicate
// references a parameter name that doesn't match any actual function parameter.

type TypeA = { kind: 'a' };
type TypeB = { kind: 'b' };
type UnionType = TypeA | TypeB;

function isTypeA(
_value: UnionType
): value is TypeA { // "value" doesn't match parameter "_value"
~~~~~
!!! error TS1225: Cannot find parameter 'value'.
return true;
}

function test(input: UnionType): void {
if (isTypeA(input)) {
console.log(input.kind);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//// [tests/cases/compiler/typePredicateParameterMismatch.ts] ////

=== typePredicateParameterMismatch.ts ===
// This test verifies that the checker doesn't panic when a type predicate
// references a parameter name that doesn't match any actual function parameter.

type TypeA = { kind: 'a' };
>TypeA : Symbol(TypeA, Decl(typePredicateParameterMismatch.ts, 0, 0))
>kind : Symbol(kind, Decl(typePredicateParameterMismatch.ts, 3, 14))

type TypeB = { kind: 'b' };
>TypeB : Symbol(TypeB, Decl(typePredicateParameterMismatch.ts, 3, 27))
>kind : Symbol(kind, Decl(typePredicateParameterMismatch.ts, 4, 14))

type UnionType = TypeA | TypeB;
>UnionType : Symbol(UnionType, Decl(typePredicateParameterMismatch.ts, 4, 27))
>TypeA : Symbol(TypeA, Decl(typePredicateParameterMismatch.ts, 0, 0))
>TypeB : Symbol(TypeB, Decl(typePredicateParameterMismatch.ts, 3, 27))

function isTypeA(
>isTypeA : Symbol(isTypeA, Decl(typePredicateParameterMismatch.ts, 5, 31))

_value: UnionType
>_value : Symbol(_value, Decl(typePredicateParameterMismatch.ts, 7, 17))
>UnionType : Symbol(UnionType, Decl(typePredicateParameterMismatch.ts, 4, 27))

): value is TypeA { // "value" doesn't match parameter "_value"
>TypeA : Symbol(TypeA, Decl(typePredicateParameterMismatch.ts, 0, 0))

return true;
}

function test(input: UnionType): void {
>test : Symbol(test, Decl(typePredicateParameterMismatch.ts, 11, 1))
>input : Symbol(input, Decl(typePredicateParameterMismatch.ts, 13, 14))
>UnionType : Symbol(UnionType, Decl(typePredicateParameterMismatch.ts, 4, 27))

if (isTypeA(input)) {
>isTypeA : Symbol(isTypeA, Decl(typePredicateParameterMismatch.ts, 5, 31))
>input : Symbol(input, Decl(typePredicateParameterMismatch.ts, 13, 14))

console.log(input.kind);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>input.kind : Symbol(kind, Decl(typePredicateParameterMismatch.ts, 3, 14), Decl(typePredicateParameterMismatch.ts, 4, 14))
>input : Symbol(input, Decl(typePredicateParameterMismatch.ts, 13, 14))
>kind : Symbol(kind, Decl(typePredicateParameterMismatch.ts, 3, 14), Decl(typePredicateParameterMismatch.ts, 4, 14))
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//// [tests/cases/compiler/typePredicateParameterMismatch.ts] ////

=== typePredicateParameterMismatch.ts ===
// This test verifies that the checker doesn't panic when a type predicate
// references a parameter name that doesn't match any actual function parameter.

type TypeA = { kind: 'a' };
>TypeA : TypeA
>kind : "a"

type TypeB = { kind: 'b' };
>TypeB : TypeB
>kind : "b"

type UnionType = TypeA | TypeB;
>UnionType : UnionType

function isTypeA(
>isTypeA : (_value: UnionType) => value is TypeA

_value: UnionType
>_value : UnionType

): value is TypeA { // "value" doesn't match parameter "_value"
return true;
>true : true
}

function test(input: UnionType): void {
>test : (input: UnionType) => void
>input : UnionType

if (isTypeA(input)) {
>isTypeA(input) : boolean
>isTypeA : (_value: UnionType) => value is TypeA
>input : UnionType

console.log(input.kind);
>console.log(input.kind) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>input.kind : "a" | "b"
>input : UnionType
>kind : "a" | "b"
}
}

19 changes: 19 additions & 0 deletions testdata/tests/cases/compiler/assertsPredicateParameterMismatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// @strict: true
// @noemit: true

// This test verifies that the checker doesn't panic when an assertion predicate
// references a parameter name that doesn't match any actual function parameter.
// This specifically tests the code path in isReachableFlowNodeWorker.

function assertCondition(
_condition: boolean
): asserts condition { // "condition" doesn't match parameter "_condition"
if (!_condition) {
throw new Error('Condition failed');
}
}

function test(): void {
assertCondition(false);
console.log("unreachable");
}
21 changes: 21 additions & 0 deletions testdata/tests/cases/compiler/typePredicateParameterMismatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @strict: true
// @noemit: true

// This test verifies that the checker doesn't panic when a type predicate
// references a parameter name that doesn't match any actual function parameter.

type TypeA = { kind: 'a' };
type TypeB = { kind: 'b' };
type UnionType = TypeA | TypeB;

function isTypeA(
_value: UnionType
): value is TypeA { // "value" doesn't match parameter "_value"
return true;
}

function test(input: UnionType): void {
if (isTypeA(input)) {
console.log(input.kind);
}
}
Loading